From 8f39f028e654fd1ae85ed2c55d645b762a8a38b3 Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Tue, 9 May 2023 17:31:51 +0100 Subject: [PATCH 001/364] feat: Additional models as data extensions - `logging`, `ldap`, and `url-redirect` sinks --- csharp/ql/lib/change-notes/2023-05-09-models-as-data.md | 4 ++++ .../code/csharp/security/dataflow/LDAPInjectionQuery.qll | 6 ++++++ .../code/csharp/security/dataflow/LogForgingQuery.qll | 6 ++++++ .../code/csharp/security/dataflow/UrlRedirectQuery.qll | 6 ++++++ 4 files changed, 22 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2023-05-09-models-as-data.md diff --git a/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md b/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md new file mode 100644 index 00000000000..ef7e8a808b6 --- /dev/null +++ b/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Additional support for `logging`, `ldap`, and `url-redirect` sink kinds for Models as Data. \ No newline at end of file diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll index 9171bae41b4..0e1afdbef7e 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll @@ -8,6 +8,7 @@ private import semmle.code.csharp.security.dataflow.flowsources.Remote private import semmle.code.csharp.frameworks.system.DirectoryServices private import semmle.code.csharp.frameworks.system.directoryservices.Protocols private import semmle.code.csharp.security.Sanitizers +private import semmle.code.csharp.dataflow.ExternalFlow /** * A data flow source for unvalidated user input that is used to construct LDAP queries. @@ -68,6 +69,11 @@ module LdapInjection = TaintTracking::Global; /** A source of remote user input. */ class RemoteSource extends Source instanceof RemoteFlowSource { } +/** LDAP sinks defined through Models as Data. */ +private class ExternalLDAPExprSink extends Sink { + ExternalLDAPExprSink() { sinkNode(this, "ldap") } +} + /** * An argument that sets the `Path` property of a `DirectoryEntry` object that is a sink for LDAP * injection. diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll index f145b18dfeb..e304a7be1c5 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll @@ -8,6 +8,7 @@ private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.text.RegularExpressions private import semmle.code.csharp.security.Sanitizers private import semmle.code.csharp.security.dataflow.flowsinks.ExternalLocationSink +private import semmle.code.csharp.dataflow.ExternalFlow /** * A data flow source for untrusted user input used in log entries. @@ -72,6 +73,11 @@ private class LogForgingLogMessageSink extends Sink, LogMessageSink { } */ private class LogForgingTraceMessageSink extends Sink, TraceMessageSink { } +/** Log Forging sinks defined through Models as Data. */ +private class ExternalLDAPExprSink extends Sink { + ExternalLDAPExprSink() { sinkNode(this, "logging") } +} + /** * A call to String replace or remove that is considered to sanitize replaced string. */ diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll index 44b90cf3096..d6f32722792 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll @@ -9,6 +9,7 @@ private import semmle.code.csharp.frameworks.system.Web private import semmle.code.csharp.frameworks.system.web.Mvc private import semmle.code.csharp.security.Sanitizers private import semmle.code.csharp.frameworks.microsoft.AspNetCore +private import semmle.code.csharp.dataflow.ExternalFlow /** * A data flow source for unvalidated URL redirect vulnerabilities. @@ -70,6 +71,11 @@ module UrlRedirect = TaintTracking::Global; /** A source of remote user input. */ class RemoteSource extends Source instanceof RemoteFlowSource { } +/** URL Redirection sinks defined through Models as Data. */ +private class ExternalLDAPExprSink extends Sink { + ExternalLDAPExprSink() { sinkNode(this, "url-redirect") } +} + /** * A URL argument to a call to `HttpResponse.Redirect()` or `Controller.Redirect()`, that is a * sink for URL redirects. From 632e48745823ef8df32e9d2749c50cc4ca0dc3fb Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Tue, 9 May 2023 17:37:00 +0100 Subject: [PATCH 002/364] Add Command Injection support --- .../code/csharp/security/dataflow/CommandInjectionQuery.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll index 265cae5f08a..7572d696459 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll @@ -6,6 +6,7 @@ import csharp private import semmle.code.csharp.security.dataflow.flowsources.Remote private import semmle.code.csharp.frameworks.system.Diagnostics private import semmle.code.csharp.security.Sanitizers +private import semmle.code.csharp.dataflow.ExternalFlow /** * A source specific to command injection vulnerabilities. @@ -66,6 +67,11 @@ module CommandInjection = TaintTracking::Global; /** A source of remote user input. */ class RemoteSource extends Source instanceof RemoteFlowSource { } +/** Command Injection sinks defined through CSV models. */ +private class ExternalCommandInjectionExprSink extends Sink { + ExternalCommandInjectionExprSink() { sinkNode(this, "command-injection") } +} + /** * A sink in `System.Diagnostic.Process` or its related classes. */ From e84657242c106eabb3b91dc32ecff4806b41b780 Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Tue, 9 May 2023 17:38:15 +0100 Subject: [PATCH 003/364] Fix names --- .../semmle/code/csharp/security/dataflow/LogForgingQuery.qll | 4 ++-- .../semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll index e304a7be1c5..9b17342345c 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll @@ -74,8 +74,8 @@ private class LogForgingLogMessageSink extends Sink, LogMessageSink { } private class LogForgingTraceMessageSink extends Sink, TraceMessageSink { } /** Log Forging sinks defined through Models as Data. */ -private class ExternalLDAPExprSink extends Sink { - ExternalLDAPExprSink() { sinkNode(this, "logging") } +private class ExternalLoggingExprSink extends Sink { + ExternalLoggingExprSink() { sinkNode(this, "logging") } } /** diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll index d6f32722792..66cdee8f2cc 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll @@ -72,8 +72,8 @@ module UrlRedirect = TaintTracking::Global; class RemoteSource extends Source instanceof RemoteFlowSource { } /** URL Redirection sinks defined through Models as Data. */ -private class ExternalLDAPExprSink extends Sink { - ExternalLDAPExprSink() { sinkNode(this, "url-redirect") } +private class ExternalUrlRedirectExprSink extends Sink { + ExternalUrlRedirectExprSink() { sinkNode(this, "url-redirect") } } /** From 7b55955fac59fb3183f82f4145b533999f2b9e9d Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Tue, 9 May 2023 17:40:12 +0100 Subject: [PATCH 004/364] Update change notes --- csharp/ql/lib/change-notes/2023-05-09-models-as-data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md b/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md index ef7e8a808b6..eec683c707c 100644 --- a/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md +++ b/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* Additional support for `logging`, `ldap`, and `url-redirect` sink kinds for Models as Data. \ No newline at end of file +* Additional support for `logging`, `ldap`, `command-injection`, and `url-redirect` sink kinds for Models as Data. \ No newline at end of file From 0e932574f45e51523fbf89898f7b3cc8fa6f8b66 Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Tue, 9 May 2023 17:42:17 +0100 Subject: [PATCH 005/364] Fix Ldap class name --- .../code/csharp/security/dataflow/LDAPInjectionQuery.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll index 0e1afdbef7e..ba18e27e33c 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll @@ -70,8 +70,8 @@ module LdapInjection = TaintTracking::Global; class RemoteSource extends Source instanceof RemoteFlowSource { } /** LDAP sinks defined through Models as Data. */ -private class ExternalLDAPExprSink extends Sink { - ExternalLDAPExprSink() { sinkNode(this, "ldap") } +private class ExternalLdapExprSink extends Sink { + ExternalLdapExprSink() { sinkNode(this, "ldap") } } /** From 0f85b98cc771d5da6c6c98622af7cd65c9a17d6c Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Wed, 10 May 2023 10:00:16 +0100 Subject: [PATCH 006/364] Update models to match new data extensions names --- .../semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll | 2 +- .../semmle/code/csharp/security/dataflow/LogForgingQuery.qll | 2 +- .../semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll index ba18e27e33c..838fb2f373b 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll @@ -71,7 +71,7 @@ class RemoteSource extends Source instanceof RemoteFlowSource { } /** LDAP sinks defined through Models as Data. */ private class ExternalLdapExprSink extends Sink { - ExternalLdapExprSink() { sinkNode(this, "ldap") } + ExternalLdapExprSink() { sinkNode(this, "ldap-injection") } } /** diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll index 9b17342345c..e219b5db589 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll @@ -75,7 +75,7 @@ private class LogForgingTraceMessageSink extends Sink, TraceMessageSink { } /** Log Forging sinks defined through Models as Data. */ private class ExternalLoggingExprSink extends Sink { - ExternalLoggingExprSink() { sinkNode(this, "logging") } + ExternalLoggingExprSink() { sinkNode(this, "log-injection") } } /** diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll index 66cdee8f2cc..56c409b38b5 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll @@ -73,7 +73,7 @@ class RemoteSource extends Source instanceof RemoteFlowSource { } /** URL Redirection sinks defined through Models as Data. */ private class ExternalUrlRedirectExprSink extends Sink { - ExternalUrlRedirectExprSink() { sinkNode(this, "url-redirect") } + ExternalUrlRedirectExprSink() { sinkNode(this, "url-redirection") } } /** From 681623d631f24726faa7a9e663fe921ee9a3d57c Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Wed, 10 May 2023 10:06:22 +0100 Subject: [PATCH 007/364] Update kind model validation --- csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 1f57626840b..0ce50e54a3a 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -211,7 +211,11 @@ module ModelValidation { ) or exists(string kind | sinkModel(_, _, _, _, _, _, _, kind, _) | - not kind = ["code", "sql", "xss", "remote", "html"] and + not kind = + [ + "code", "command-injection", "html", "ldap-injection", "log-injection", "remote", "sql", + "url-redirection", "xss", + ] and not kind.matches("encryption-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) From bffc233d865f38a0ce20ec163847f6206c60a32d Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Wed, 10 May 2023 10:09:19 +0100 Subject: [PATCH 008/364] Update release notes --- csharp/ql/lib/change-notes/2023-05-09-models-as-data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md b/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md index eec683c707c..c0abd8f06c0 100644 --- a/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md +++ b/csharp/ql/lib/change-notes/2023-05-09-models-as-data.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* Additional support for `logging`, `ldap`, `command-injection`, and `url-redirect` sink kinds for Models as Data. \ No newline at end of file +* Additional support for `command-injection`, `ldap-injection`, `log-injection`, and `url-redirection` sink kinds for Models as Data. \ No newline at end of file From a276cc3094862274e7a4411cf53ec2b8cb00065f Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Wed, 19 Apr 2023 17:09:24 +0200 Subject: [PATCH 009/364] Convert all command injection sinks to MaD format --- .../2023-04-19-deprecated-execcallable.md | 4 +++ .../experimental/com.jcraft.jsch.model.yml | 6 ++++ java/ql/lib/ext/java.lang.model.yml | 27 ++++++++------- .../lib/ext/org.apache.commons.exec.model.yml | 9 +++++ java/ql/lib/semmle/code/java/JDK.qll | 34 ------------------- .../code/java/frameworks/apache/Exec.qll | 29 ---------------- .../code/java/security/CommandLineQuery.qll | 10 +++--- .../code/java/security/ExternalProcess.qll | 31 +++++++++-------- .../Security/CWE/CWE-078/ExecTaintedLocal.ql | 11 +++--- .../src/Security/CWE/CWE-078/ExecUnescaped.ql | 1 + .../Security/CWE/CWE-078/ExecTainted.ql | 6 +++- .../Security/CWE/CWE-078/JSchOSInjection.qll | 20 ----------- .../CWE-078/ExecTaintedLocal.expected | 20 +++++++---- 13 files changed, 81 insertions(+), 127 deletions(-) create mode 100644 java/ql/lib/change-notes/2023-04-19-deprecated-execcallable.md create mode 100644 java/ql/lib/ext/experimental/com.jcraft.jsch.model.yml create mode 100644 java/ql/lib/ext/org.apache.commons.exec.model.yml delete mode 100644 java/ql/lib/semmle/code/java/frameworks/apache/Exec.qll delete mode 100644 java/ql/src/experimental/Security/CWE/CWE-078/JSchOSInjection.qll diff --git a/java/ql/lib/change-notes/2023-04-19-deprecated-execcallable.md b/java/ql/lib/change-notes/2023-04-19-deprecated-execcallable.md new file mode 100644 index 00000000000..fc21d1825bf --- /dev/null +++ b/java/ql/lib/change-notes/2023-04-19-deprecated-execcallable.md @@ -0,0 +1,4 @@ +--- +category: deprecated +--- +* The `ExecCallable` class in `ExternalProcess.qll` has been deprecated. diff --git a/java/ql/lib/ext/experimental/com.jcraft.jsch.model.yml b/java/ql/lib/ext/experimental/com.jcraft.jsch.model.yml new file mode 100644 index 00000000000..1a8783d91a5 --- /dev/null +++ b/java/ql/lib/ext/experimental/com.jcraft.jsch.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: experimentalSinkModel + data: + - ["com.jcraft.jsch", "ChannelExec", True, "setCommand", "", "", "Argument[0]", "command-injection", "manual", "jsch-os-injection"] diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml index bbb269b3d55..59eb548af27 100644 --- a/java/ql/lib/ext/java.lang.model.yml +++ b/java/ql/lib/ext/java.lang.model.yml @@ -8,19 +8,20 @@ extensions: - ["java.lang", "ClassLoader", True, "getSystemResource", "(String)", "", "Argument[0]", "read-file", "ai-manual"] - ["java.lang", "ClassLoader", True, "getSystemResourceAsStream", "(String)", "", "Argument[0]", "read-file", "ai-manual"] - ["java.lang", "Module", True, "getResourceAsStream", "(String)", "", "Argument[0]", "read-file", "ai-manual"] - # These are modeled in plain CodeQL. TODO: migrate them. - # - ["java.lang", "ProcessBuilder", False, "command", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] - # - ["java.lang", "ProcessBuilder", False, "directory", "(File)", "", "Argument[0]", "command-injection", "ai-manual"] - # - ["java.lang", "ProcessBuilder", False, "ProcessBuilder", "(List)", "", "Argument[0]", "command-injection", "ai-manual"] - # - ["java.lang", "ProcessBuilder", False, "ProcessBuilder", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] - # - ["java.lang", "Runtime", True, "exec", "(String,String[])", "", "Argument[0]", "command-injection", "ai-manual"] - # - ["java.lang", "Runtime", True, "exec", "(String[],String[])", "", "Argument[0]", "command-injection", "ai-manual"] - # - ["java.lang", "Runtime", True, "exec", "(String,String[],File)", "", "Argument[0]", "command-injection", "ai-manual"] - # - ["java.lang", "Runtime", True, "exec", "(String,String[],File)", "", "Argument[2]", "command-injection", "ai-manual"] - # - ["java.lang", "Runtime", True, "exec", "(String)", "", "Argument[0]", "command-injection", "ai-manual"] - # - ["java.lang", "Runtime", True, "exec", "(String[],String[],File)", "", "Argument[0]", "command-injection", "ai-manual"] - # - ["java.lang", "Runtime", True, "exec", "(String[],String[],File)", "", "Argument[2]", "command-injection", "ai-manual"] - # - ["java.lang", "Runtime", True, "exec", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "ProcessBuilder", False, "command", "(List)", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "ProcessBuilder", False, "command", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "ProcessBuilder", False, "command", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "ProcessBuilder", False, "directory", "(File)", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "ProcessBuilder", False, "ProcessBuilder", "(List)", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "ProcessBuilder", False, "ProcessBuilder", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "Runtime", True, "exec", "(String)", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "Runtime", True, "exec", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "Runtime", True, "exec", "(String[],String[])", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "Runtime", True, "exec", "(String[],String[],File)", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "Runtime", True, "exec", "(String[],String[],File)", "", "Argument[2]", "command-injection", "ai-manual"] + - ["java.lang", "Runtime", True, "exec", "(String,String[])", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "Runtime", True, "exec", "(String,String[],File)", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "Runtime", True, "exec", "(String,String[],File)", "", "Argument[2]", "command-injection", "ai-manual"] - ["java.lang", "String", False, "matches", "(String)", "", "Argument[0]", "regex-use[f-1]", "manual"] - ["java.lang", "String", False, "replaceAll", "(String,String)", "", "Argument[0]", "regex-use[-1]", "manual"] - ["java.lang", "String", False, "replaceFirst", "(String,String)", "", "Argument[0]", "regex-use[-1]", "manual"] diff --git a/java/ql/lib/ext/org.apache.commons.exec.model.yml b/java/ql/lib/ext/org.apache.commons.exec.model.yml new file mode 100644 index 00000000000..7b65ee46a49 --- /dev/null +++ b/java/ql/lib/ext/org.apache.commons.exec.model.yml @@ -0,0 +1,9 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.apache.commons.exec", "CommandLine", True, "parse", "(String)", "", "Argument[0]", "command-injection", "manual"] + - ["org.apache.commons.exec", "CommandLine", True, "parse", "(String,Map)", "", "Argument[0]", "command-injection", "manual"] + - ["org.apache.commons.exec", "CommandLine", True, "addArguments", "(String)", "", "Argument[0]", "command-injection", "manual"] + - ["org.apache.commons.exec", "CommandLine", True, "addArguments", "(String,boolean)", "", "Argument[0]", "command-injection", "manual"] diff --git a/java/ql/lib/semmle/code/java/JDK.qll b/java/ql/lib/semmle/code/java/JDK.qll index 78f7defc32f..62115884c62 100644 --- a/java/ql/lib/semmle/code/java/JDK.qll +++ b/java/ql/lib/semmle/code/java/JDK.qll @@ -3,7 +3,6 @@ */ import Member -import semmle.code.java.security.ExternalProcess private import semmle.code.java.dataflow.FlowSteps // --- Standard types --- @@ -198,39 +197,6 @@ class TypeFile extends Class { } // --- Standard methods --- -/** - * Any constructor of class `java.lang.ProcessBuilder`. - */ -class ProcessBuilderConstructor extends Constructor, ExecCallable { - ProcessBuilderConstructor() { this.getDeclaringType() instanceof TypeProcessBuilder } - - override int getAnExecutedArgument() { result = 0 } -} - -/** - * Any of the methods named `command` on class `java.lang.ProcessBuilder`. - */ -class MethodProcessBuilderCommand extends Method, ExecCallable { - MethodProcessBuilderCommand() { - this.hasName("command") and - this.getDeclaringType() instanceof TypeProcessBuilder - } - - override int getAnExecutedArgument() { result = 0 } -} - -/** - * Any method named `exec` on class `java.lang.Runtime`. - */ -class MethodRuntimeExec extends Method, ExecCallable { - MethodRuntimeExec() { - this.hasName("exec") and - this.getDeclaringType() instanceof TypeRuntime - } - - override int getAnExecutedArgument() { result = 0 } -} - /** * Any method named `getenv` on class `java.lang.System`. */ diff --git a/java/ql/lib/semmle/code/java/frameworks/apache/Exec.qll b/java/ql/lib/semmle/code/java/frameworks/apache/Exec.qll deleted file mode 100644 index d6876bfae70..00000000000 --- a/java/ql/lib/semmle/code/java/frameworks/apache/Exec.qll +++ /dev/null @@ -1,29 +0,0 @@ -/** Definitions related to the Apache Commons Exec library. */ - -import semmle.code.java.Type -import semmle.code.java.security.ExternalProcess - -/** The class `org.apache.commons.exec.CommandLine`. */ -private class TypeCommandLine extends Class { - TypeCommandLine() { this.hasQualifiedName("org.apache.commons.exec", "CommandLine") } -} - -/** The `parse()` method of the class `org.apache.commons.exec.CommandLine`. */ -private class MethodCommandLineParse extends Method, ExecCallable { - MethodCommandLineParse() { - this.getDeclaringType() instanceof TypeCommandLine and - this.hasName("parse") - } - - override int getAnExecutedArgument() { result = 0 } -} - -/** The `addArguments()` method of the class `org.apache.commons.exec.CommandLine`. */ -private class MethodCommandLineAddArguments extends Method, ExecCallable { - MethodCommandLineAddArguments() { - this.getDeclaringType() instanceof TypeCommandLine and - this.hasName("addArguments") - } - - override int getAnExecutedArgument() { result = 0 } -} diff --git a/java/ql/lib/semmle/code/java/security/CommandLineQuery.qll b/java/ql/lib/semmle/code/java/security/CommandLineQuery.qll index b6e3f5b188a..c0d09a9eeab 100644 --- a/java/ql/lib/semmle/code/java/security/CommandLineQuery.qll +++ b/java/ql/lib/semmle/code/java/security/CommandLineQuery.qll @@ -10,8 +10,8 @@ import java private import semmle.code.java.dataflow.FlowSources private import semmle.code.java.dataflow.ExternalFlow -private import semmle.code.java.security.ExternalProcess private import semmle.code.java.security.CommandArguments +private import semmle.code.java.security.ExternalProcess /** A sink for command injection vulnerabilities. */ abstract class CommandInjectionSink extends DataFlow::Node { } @@ -33,9 +33,7 @@ class CommandInjectionAdditionalTaintStep extends Unit { } private class DefaultCommandInjectionSink extends CommandInjectionSink { - DefaultCommandInjectionSink() { - this.asExpr() instanceof ArgumentToExec or sinkNode(this, "command-injection") - } + DefaultCommandInjectionSink() { sinkNode(this, "command-injection") } } private class DefaultCommandInjectionSanitizer extends CommandInjectionSanitizer { @@ -100,7 +98,7 @@ predicate execIsTainted( RemoteUserInputToArgumentToExecFlow::PathNode sink, Expr execArg ) { RemoteUserInputToArgumentToExecFlow::flowPath(source, sink) and - sink.getNode().asExpr() = execArg + argumentToExec(execArg, sink.getNode()) } /** @@ -112,7 +110,7 @@ predicate execIsTainted( */ deprecated predicate execTainted(DataFlow::PathNode source, DataFlow::PathNode sink, Expr execArg) { exists(RemoteUserInputToArgumentToExecFlowConfig conf | - conf.hasFlowPath(source, sink) and sink.getNode().asExpr() = execArg + conf.hasFlowPath(source, sink) and argumentToExec(execArg, sink.getNode()) ) } diff --git a/java/ql/lib/semmle/code/java/security/ExternalProcess.qll b/java/ql/lib/semmle/code/java/security/ExternalProcess.qll index 9a061c7a419..385d2f6c548 100644 --- a/java/ql/lib/semmle/code/java/security/ExternalProcess.qll +++ b/java/ql/lib/semmle/code/java/security/ExternalProcess.qll @@ -1,16 +1,13 @@ /** Definitions related to external processes. */ import semmle.code.java.Member - -private module Instances { - private import semmle.code.java.JDK - private import semmle.code.java.frameworks.apache.Exec -} +private import semmle.code.java.dataflow.DataFlow +private import semmle.code.java.security.CommandLineQuery /** - * A callable that executes a command. + * DEPRECATED: A callable that executes a command. */ -abstract class ExecCallable extends Callable { +abstract deprecated class ExecCallable extends Callable { /** * Gets the index of an argument that will be part of the command that is executed. */ @@ -23,13 +20,19 @@ abstract class ExecCallable extends Callable { * to be executed. */ class ArgumentToExec extends Expr { - ArgumentToExec() { - exists(Call execCall, ExecCallable execCallable, int i | - execCall.getArgument(pragma[only_bind_into](i)) = this and - execCallable = execCall.getCallee() and - i = execCallable.getAnExecutedArgument() - ) - } + ArgumentToExec() { argumentToExec(this, _) } +} + +/** + * Holds if `e` is an expression used as an argument to a call that executes an external command. + * For calls to varargs method calls, this only includes the first argument, which will be the command + * to be executed. + */ +predicate argumentToExec(Expr e, CommandInjectionSink s) { + s.asExpr() = e + or + e.(Argument).isNthVararg(0) and + s.(DataFlow::ImplicitVarargsArray).getCall() = e.(Argument).getCall() } /** diff --git a/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql b/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql index 08c230cb43a..38b79c468cd 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql +++ b/java/ql/src/Security/CWE/CWE-078/ExecTaintedLocal.ql @@ -14,11 +14,14 @@ import java import semmle.code.java.security.CommandLineQuery +import semmle.code.java.security.ExternalProcess import LocalUserInputToArgumentToExecFlow::PathGraph from LocalUserInputToArgumentToExecFlow::PathNode source, - LocalUserInputToArgumentToExecFlow::PathNode sink -where LocalUserInputToArgumentToExecFlow::flowPath(source, sink) -select sink.getNode().asExpr(), source, sink, "This command line depends on a $@.", - source.getNode(), "user-provided value" + LocalUserInputToArgumentToExecFlow::PathNode sink, Expr e +where + LocalUserInputToArgumentToExecFlow::flowPath(source, sink) and + argumentToExec(e, sink.getNode()) +select e, source, sink, "This command line depends on a $@.", source.getNode(), + "user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql index 68e3cc2faa7..d50f583bbfe 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql +++ b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql @@ -14,6 +14,7 @@ import java import semmle.code.java.security.CommandLineQuery +import semmle.code.java.security.ExternalProcess /** * Strings that are known to be sane by some simple local analysis. Such strings diff --git a/java/ql/src/experimental/Security/CWE/CWE-078/ExecTainted.ql b/java/ql/src/experimental/Security/CWE/CWE-078/ExecTainted.ql index 4305b9fbabc..5d543d65011 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-078/ExecTainted.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-078/ExecTainted.ql @@ -15,7 +15,11 @@ import java import semmle.code.java.security.CommandLineQuery import RemoteUserInputToArgumentToExecFlow::PathGraph -import JSchOSInjection +private import semmle.code.java.dataflow.ExternalFlow + +private class ActivateModels extends ActiveExperimentalModels { + ActivateModels() { this = "jsch-os-injection" } +} // This is a clone of query `java/command-line-injection` that also includes experimental sinks. from diff --git a/java/ql/src/experimental/Security/CWE/CWE-078/JSchOSInjection.qll b/java/ql/src/experimental/Security/CWE/CWE-078/JSchOSInjection.qll deleted file mode 100644 index ec1f4d0adfa..00000000000 --- a/java/ql/src/experimental/Security/CWE/CWE-078/JSchOSInjection.qll +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Provides classes for JSch OS command injection detection - */ - -import java - -/** The class `com.jcraft.jsch.ChannelExec`. */ -private class JSchChannelExec extends RefType { - JSchChannelExec() { this.hasQualifiedName("com.jcraft.jsch", "ChannelExec") } -} - -/** A method to set an OS Command for the execution. */ -private class ChannelExecSetCommandMethod extends Method, ExecCallable { - ChannelExecSetCommandMethod() { - this.hasName("setCommand") and - this.getDeclaringType() instanceof JSchChannelExec - } - - override int getAnExecutedArgument() { result = 0 } -} diff --git a/java/ql/test/query-tests/security/CWE-078/ExecTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-078/ExecTaintedLocal.expected index 2ae893b5d1d..4616bd7c808 100644 --- a/java/ql/test/query-tests/security/CWE-078/ExecTaintedLocal.expected +++ b/java/ql/test/query-tests/security/CWE-078/ExecTaintedLocal.expected @@ -1,22 +1,28 @@ edges -| Test.java:6:35:6:44 | arg : String | Test.java:7:44:7:69 | ... + ... | +| Test.java:6:35:6:44 | arg : String | Test.java:7:44:7:69 | ... + ... : String | | Test.java:6:35:6:44 | arg : String | Test.java:10:61:10:73 | ... + ... : String | | Test.java:6:35:6:44 | arg : String | Test.java:16:13:16:25 | ... + ... : String | | Test.java:6:35:6:44 | arg : String | Test.java:22:15:22:27 | ... + ... : String | +| Test.java:7:25:7:70 | new ..[] { .. } : String[] [[]] : String | Test.java:7:25:7:70 | new ..[] { .. } | +| Test.java:7:44:7:69 | ... + ... : String | Test.java:7:25:7:70 | new ..[] { .. } : String[] [[]] : String | | Test.java:10:29:10:74 | {...} : String[] [[]] : String | Test.java:10:29:10:74 | new String[] | | Test.java:10:61:10:73 | ... + ... : String | Test.java:10:29:10:74 | {...} : String[] [[]] : String | | Test.java:16:5:16:7 | cmd [post update] : List [] : String | Test.java:18:29:18:31 | cmd | | Test.java:16:13:16:25 | ... + ... : String | Test.java:16:5:16:7 | cmd [post update] : List [] : String | | Test.java:22:5:22:8 | cmd1 [post update] : String[] [[]] : String | Test.java:24:29:24:32 | cmd1 | | Test.java:22:15:22:27 | ... + ... : String | Test.java:22:5:22:8 | cmd1 [post update] : String[] [[]] : String | -| Test.java:28:38:28:47 | arg : String | Test.java:29:44:29:64 | ... + ... | +| Test.java:28:38:28:47 | arg : String | Test.java:29:44:29:64 | ... + ... : String | +| Test.java:29:25:29:65 | new ..[] { .. } : String[] [[]] : String | Test.java:29:25:29:65 | new ..[] { .. } | +| Test.java:29:44:29:64 | ... + ... : String | Test.java:29:25:29:65 | new ..[] { .. } : String[] [[]] : String | | Test.java:57:27:57:39 | args : String[] | Test.java:60:20:60:22 | arg : String | | Test.java:57:27:57:39 | args : String[] | Test.java:61:23:61:25 | arg : String | | Test.java:60:20:60:22 | arg : String | Test.java:6:35:6:44 | arg : String | | Test.java:61:23:61:25 | arg : String | Test.java:28:38:28:47 | arg : String | nodes | Test.java:6:35:6:44 | arg : String | semmle.label | arg : String | -| Test.java:7:44:7:69 | ... + ... | semmle.label | ... + ... | +| Test.java:7:25:7:70 | new ..[] { .. } | semmle.label | new ..[] { .. } | +| Test.java:7:25:7:70 | new ..[] { .. } : String[] [[]] : String | semmle.label | new ..[] { .. } : String[] [[]] : String | +| Test.java:7:44:7:69 | ... + ... : String | semmle.label | ... + ... : String | | Test.java:10:29:10:74 | new String[] | semmle.label | new String[] | | Test.java:10:29:10:74 | {...} : String[] [[]] : String | semmle.label | {...} : String[] [[]] : String | | Test.java:10:61:10:73 | ... + ... : String | semmle.label | ... + ... : String | @@ -27,14 +33,16 @@ nodes | Test.java:22:15:22:27 | ... + ... : String | semmle.label | ... + ... : String | | Test.java:24:29:24:32 | cmd1 | semmle.label | cmd1 | | Test.java:28:38:28:47 | arg : String | semmle.label | arg : String | -| Test.java:29:44:29:64 | ... + ... | semmle.label | ... + ... | +| Test.java:29:25:29:65 | new ..[] { .. } | semmle.label | new ..[] { .. } | +| Test.java:29:25:29:65 | new ..[] { .. } : String[] [[]] : String | semmle.label | new ..[] { .. } : String[] [[]] : String | +| Test.java:29:44:29:64 | ... + ... : String | semmle.label | ... + ... : String | | Test.java:57:27:57:39 | args : String[] | semmle.label | args : String[] | | Test.java:60:20:60:22 | arg : String | semmle.label | arg : String | | Test.java:61:23:61:25 | arg : String | semmle.label | arg : String | subpaths #select -| Test.java:7:44:7:69 | ... + ... | Test.java:57:27:57:39 | args : String[] | Test.java:7:44:7:69 | ... + ... | This command line depends on a $@. | Test.java:57:27:57:39 | args | user-provided value | +| Test.java:7:44:7:69 | ... + ... | Test.java:57:27:57:39 | args : String[] | Test.java:7:25:7:70 | new ..[] { .. } | This command line depends on a $@. | Test.java:57:27:57:39 | args | user-provided value | | Test.java:10:29:10:74 | new String[] | Test.java:57:27:57:39 | args : String[] | Test.java:10:29:10:74 | new String[] | This command line depends on a $@. | Test.java:57:27:57:39 | args | user-provided value | | Test.java:18:29:18:31 | cmd | Test.java:57:27:57:39 | args : String[] | Test.java:18:29:18:31 | cmd | This command line depends on a $@. | Test.java:57:27:57:39 | args | user-provided value | | Test.java:24:29:24:32 | cmd1 | Test.java:57:27:57:39 | args : String[] | Test.java:24:29:24:32 | cmd1 | This command line depends on a $@. | Test.java:57:27:57:39 | args | user-provided value | -| Test.java:29:44:29:64 | ... + ... | Test.java:57:27:57:39 | args : String[] | Test.java:29:44:29:64 | ... + ... | This command line depends on a $@. | Test.java:57:27:57:39 | args | user-provided value | +| Test.java:29:44:29:64 | ... + ... | Test.java:57:27:57:39 | args : String[] | Test.java:29:25:29:65 | new ..[] { .. } | This command line depends on a $@. | Test.java:57:27:57:39 | args | user-provided value | From 6e230e10f8205436e617581b9b2ac7844634d4a5 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 10 May 2023 15:28:01 -0400 Subject: [PATCH 010/364] C++: include stack-allocated arrays in off-by-one query --- .../CWE/CWE-193/ConstantSizeArrayOffByOne.ql | 49 ++++++++++--------- .../ConstantSizeArrayOffByOne.expected | 4 ++ .../CWE/CWE-193/constant-size/test.cpp | 8 +++ 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql index 88db396f2cf..0f8609c3c43 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql @@ -14,7 +14,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysi import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.dataflow.DataFlow -import FieldAddressToDerefFlow::PathGraph +import ArrayAddressToDerefFlow::PathGraph pragma[nomagic] Instruction getABoundIn(SemBound b, IRFunction func) { @@ -79,10 +79,10 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string } predicate pointerArithOverflow0( - PointerArithmeticInstruction pai, Field f, int size, int bound, int delta + PointerArithmeticInstruction pai, Variable v, int size, int bound, int delta ) { - pai.getElementSize() = f.getUnspecifiedType().(ArrayType).getBaseType().getSize() and - f.getUnspecifiedType().(ArrayType).getArraySize() = size and + pai.getElementSize() = v.getUnspecifiedType().(ArrayType).getBaseType().getSize() and + v.getUnspecifiedType().(ArrayType).getArraySize() = size and semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), bound, true, _) and delta = bound - size and delta >= 0 and @@ -105,23 +105,28 @@ module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig { module PointerArithmeticToDerefFlow = DataFlow::Global; predicate pointerArithOverflow( - PointerArithmeticInstruction pai, Field f, int size, int bound, int delta + PointerArithmeticInstruction pai, Variable v, int size, int bound, int delta ) { - pointerArithOverflow0(pai, f, size, bound, delta) and + pointerArithOverflow0(pai, v, size, bound, delta) and PointerArithmeticToDerefFlow::flow(DataFlow::instructionNode(pai), _) } -module FieldAddressToDerefConfig implements DataFlow::StateConfigSig { +module ArrayAddressToDerefConfig implements DataFlow::StateConfigSig { newtype FlowState = - additional TArray(Field f) { pointerArithOverflow(_, f, _, _, _) } or + additional TArray(Variable v) { pointerArithOverflow(_, v, _, _, _) } or additional TOverflowArithmetic(PointerArithmeticInstruction pai) { pointerArithOverflow(pai, _, _, _, _) } predicate isSource(DataFlow::Node source, FlowState state) { - exists(Field f | - source.asInstruction().(FieldAddressInstruction).getField() = f and - state = TArray(f) + exists(Variable v | + ( + source.asInstruction().(FieldAddressInstruction).getField() = v + or + source.asInstruction().(VariableAddressInstruction).getAstVariable() = v + ) and + exists(v.getUnspecifiedType().(ArrayType).getArraySize()) and + state = TArray(v) ) } @@ -141,27 +146,27 @@ module FieldAddressToDerefConfig implements DataFlow::StateConfigSig { predicate isAdditionalFlowStep( DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2 ) { - exists(PointerArithmeticInstruction pai, Field f | - state1 = TArray(f) and + exists(PointerArithmeticInstruction pai, Variable v, int size, int delta | + state1 = TArray(v) and state2 = TOverflowArithmetic(pai) and pai.getLeft() = node1.asInstruction() and node2.asInstruction() = pai and - pointerArithOverflow(pai, f, _, _, _) + pointerArithOverflow(pai, v, size, _, delta) ) } } -module FieldAddressToDerefFlow = DataFlow::GlobalWithState; +module ArrayAddressToDerefFlow = DataFlow::GlobalWithState; from - Field f, FieldAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai, - FieldAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta + Variable v, ArrayAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai, + ArrayAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta where - FieldAddressToDerefFlow::flowPath(source, sink) and +ArrayAddressToDerefFlow::flowPath(source, sink) and isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and - source.getState() = FieldAddressToDerefConfig::TArray(f) and - sink.getState() = FieldAddressToDerefConfig::TOverflowArithmetic(pai) and - pointerArithOverflow(pai, f, _, _, delta) + source.getState() = ArrayAddressToDerefConfig::TArray(v) and + sink.getState() = ArrayAddressToDerefConfig::TOverflowArithmetic(pai) and + pointerArithOverflow(pai, v, _, _, delta) select pai, source, sink, "This pointer arithmetic may have an off-by-" + (delta + 1) + - " error allowing it to overrun $@ at this $@.", f, f.getName(), deref, operation + " error allowing it to overrun $@ at this $@.", v, v.getName(), deref, operation diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected index 7d3df8cb7cb..831280a015e 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected @@ -11,6 +11,7 @@ edges | test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... | | test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p | | test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf | +| test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | nodes | test.cpp:35:5:35:22 | access to array | semmle.label | access to array | | test.cpp:35:10:35:12 | buf | semmle.label | buf | @@ -33,6 +34,8 @@ nodes | test.cpp:77:32:77:34 | buf | semmle.label | buf | | test.cpp:79:27:79:34 | buf | semmle.label | buf | | test.cpp:79:32:79:34 | buf | semmle.label | buf | +| test.cpp:128:9:128:11 | arr | semmle.label | arr | +| test.cpp:128:9:128:14 | access to array | semmle.label | access to array | subpaths #select | test.cpp:35:5:35:22 | PointerAdd: access to array | test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:35:5:35:26 | Store: ... = ... | write | @@ -44,3 +47,4 @@ subpaths | test.cpp:61:9:61:19 | PointerAdd: access to array | test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:61:9:61:23 | Store: ... = ... | write | | test.cpp:72:5:72:15 | PointerAdd: access to array | test.cpp:79:32:79:34 | buf | test.cpp:72:5:72:15 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:72:5:72:19 | Store: ... = ... | write | | test.cpp:77:27:77:44 | PointerAdd: access to array | test.cpp:77:32:77:34 | buf | test.cpp:66:32:66:32 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write | +| test.cpp:128:9:128:14 | PointerAdd: access to array | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:125:11:125:13 | arr | arr | test.cpp:128:9:128:18 | Store: ... = ... | write | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp index a33f43bfa49..64b32b9814e 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp @@ -120,3 +120,11 @@ void testEqRefinement2() { } } } + +void testStackAllocated() { + char *arr[MAX_SIZE]; + + for(int i = 0; i <= MAX_SIZE; i++) { + arr[i] = 0; // BAD + } +} From d18fb646d1550b0e12185d7ce95c6483495d5fc1 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 10 May 2023 15:35:18 -0400 Subject: [PATCH 011/364] C++: handle cast arrays properly in off-by-one query --- .../Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql | 5 ++--- .../CWE-193/constant-size/ConstantSizeArrayOffByOne.expected | 4 ++++ .../query-tests/Security/CWE/CWE-193/constant-size/test.cpp | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql index 0f8609c3c43..d6bac268b5d 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql @@ -81,8 +81,7 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string predicate pointerArithOverflow0( PointerArithmeticInstruction pai, Variable v, int size, int bound, int delta ) { - pai.getElementSize() = v.getUnspecifiedType().(ArrayType).getBaseType().getSize() and - v.getUnspecifiedType().(ArrayType).getArraySize() = size and + v.getUnspecifiedType().(ArrayType).getByteSize() / pai.getElementSize() = size and semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), bound, true, _) and delta = bound - size and delta >= 0 and @@ -162,7 +161,7 @@ from Variable v, ArrayAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai, ArrayAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta where -ArrayAddressToDerefFlow::flowPath(source, sink) and + ArrayAddressToDerefFlow::flowPath(source, sink) and isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and source.getState() = ArrayAddressToDerefConfig::TArray(v) and sink.getState() = ArrayAddressToDerefConfig::TOverflowArithmetic(pai) and diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected index 831280a015e..1555cd3f243 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected @@ -11,6 +11,7 @@ edges | test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... | | test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p | | test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf | +| test.cpp:85:34:85:36 | buf | test.cpp:88:5:88:27 | access to array | | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | nodes | test.cpp:35:5:35:22 | access to array | semmle.label | access to array | @@ -34,6 +35,8 @@ nodes | test.cpp:77:32:77:34 | buf | semmle.label | buf | | test.cpp:79:27:79:34 | buf | semmle.label | buf | | test.cpp:79:32:79:34 | buf | semmle.label | buf | +| test.cpp:85:34:85:36 | buf | semmle.label | buf | +| test.cpp:88:5:88:27 | access to array | semmle.label | access to array | | test.cpp:128:9:128:11 | arr | semmle.label | arr | | test.cpp:128:9:128:14 | access to array | semmle.label | access to array | subpaths @@ -47,4 +50,5 @@ subpaths | test.cpp:61:9:61:19 | PointerAdd: access to array | test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:61:9:61:23 | Store: ... = ... | write | | test.cpp:72:5:72:15 | PointerAdd: access to array | test.cpp:79:32:79:34 | buf | test.cpp:72:5:72:15 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:72:5:72:19 | Store: ... = ... | write | | test.cpp:77:27:77:44 | PointerAdd: access to array | test.cpp:77:32:77:34 | buf | test.cpp:66:32:66:32 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write | +| test.cpp:88:5:88:27 | PointerAdd: access to array | test.cpp:85:34:85:36 | buf | test.cpp:88:5:88:27 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:88:5:88:31 | Store: ... = ... | write | | test.cpp:128:9:128:14 | PointerAdd: access to array | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:125:11:125:13 | arr | arr | test.cpp:128:9:128:18 | Store: ... = ... | write | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp index 64b32b9814e..952b44209d4 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp @@ -85,7 +85,7 @@ void testCharIndex(BigArray *arr) { char *charBuf = (char*) arr->buf; charBuf[MAX_SIZE_BYTES - 1] = 0; // GOOD - charBuf[MAX_SIZE_BYTES] = 0; // BAD [FALSE NEGATIVE] + charBuf[MAX_SIZE_BYTES] = 0; // BAD } void testEqRefinement() { From 47b2d48da25ed1cd49c4e3dd5647b362477f2682 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 17 May 2023 23:16:59 +0200 Subject: [PATCH 012/364] python: add tests - add `getACallSimple` to `SummarizedCallable` (by adding it to `LibraryCallable`) --- .../new/internal/DataFlowDispatch.qll | 3 + .../typetracking-summaries/TestSummaries.qll | 189 ++++++++++++++++++ .../typetracking-summaries/summaries.py | 60 ++++++ .../typetracking-summaries/tracked.expected | 0 .../typetracking-summaries/tracked.ql | 36 ++++ 5 files changed, 288 insertions(+) create mode 100644 python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll create mode 100644 python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py create mode 100644 python/ql/test/experimental/dataflow/typetracking-summaries/tracked.expected create mode 100644 python/ql/test/experimental/dataflow/typetracking-summaries/tracked.ql diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index cdca96cc4ac..8dad2e8a032 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -250,6 +250,9 @@ abstract class LibraryCallable extends string { /** Gets a call to this library callable. */ abstract CallCfgNode getACall(); + /** Same as `getACall` but without referring to the call graph or API graph. */ + CallCfgNode getACallSimple() { none() } + /** Gets a data-flow node, where this library callable is used as a call-back. */ abstract ArgumentNode getACallback(); } diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll b/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll new file mode 100644 index 00000000000..1a6a504e1ee --- /dev/null +++ b/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll @@ -0,0 +1,189 @@ +private import python +private import semmle.python.dataflow.new.FlowSummary +private import semmle.python.ApiGraphs + +/** + * This module ensures that the `callStep` predicate in + * our type tracker implelemtation does not refer to the + * `getACall` predicate on `SummarizedCallable`. + */ +module RecursionGuard { + private import semmle.python.dataflow.new.internal.TypeTrackerSpecific as TT + + private class RecursionGuard extends SummarizedCallable { + RecursionGuard() { this = "RecursionGuard" } + + override DataFlow::CallCfgNode getACall() { + result.getFunction().asCfgNode().(NameNode).getId() = this and + (TT::callStep(_, _) implies any()) + } + + override DataFlow::CallCfgNode getACallSimple() { none() } + + override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } + } + + predicate test(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + TT::levelStepNoCall(nodeFrom, nodeTo) + } +} + +private class SummarizedCallableIdentity extends SummarizedCallable { + SummarizedCallableIdentity() { this = "identity" } + + override DataFlow::CallCfgNode getACall() { none() } + + override DataFlow::CallCfgNode getACallSimple() { + result.getFunction().asCfgNode().(NameNode).getId() = this + } + + override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[0]" and + output = "ReturnValue" and + preservesValue = true + } +} + +// For lambda flow to work, implement lambdaCall and lambdaCreation +private class SummarizedCallableApplyLambda extends SummarizedCallable { + SummarizedCallableApplyLambda() { this = "apply_lambda" } + + override DataFlow::CallCfgNode getACall() { none() } + + override DataFlow::CallCfgNode getACallSimple() { + result.getFunction().asCfgNode().(NameNode).getId() = this + } + + override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[1]" and + output = "Argument[0].Parameter[0]" and + preservesValue = true + or + input = "Argument[0].ReturnValue" and + output = "ReturnValue" and + preservesValue = true + } +} + +private class SummarizedCallableReversed extends SummarizedCallable { + SummarizedCallableReversed() { this = "reversed" } + + override DataFlow::CallCfgNode getACall() { none() } + + override DataFlow::CallCfgNode getACallSimple() { + result.getFunction().asCfgNode().(NameNode).getId() = this + } + + override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[0].ListElement" and + output = "ReturnValue.ListElement" and + preservesValue = true + } +} + +private class SummarizedCallableMap extends SummarizedCallable { + SummarizedCallableMap() { this = "list_map" } + + override DataFlow::CallCfgNode getACall() { none() } + + override DataFlow::CallCfgNode getACallSimple() { + result.getFunction().asCfgNode().(NameNode).getId() = this + } + + override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[1].ListElement" and + output = "Argument[0].Parameter[0]" and + preservesValue = true + or + input = "Argument[0].ReturnValue" and + output = "ReturnValue.ListElement" and + preservesValue = true + } +} + +private class SummarizedCallableAppend extends SummarizedCallable { + SummarizedCallableAppend() { this = "append_to_list" } + + override DataFlow::CallCfgNode getACall() { none() } + + override DataFlow::CallCfgNode getACallSimple() { + result.getFunction().asCfgNode().(NameNode).getId() = this + } + + override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[0]" and + output = "ReturnValue" and + preservesValue = false + or + input = "Argument[1]" and + output = "ReturnValue.ListElement" and + preservesValue = true + } +} + +private class SummarizedCallableJsonLoads extends SummarizedCallable { + SummarizedCallableJsonLoads() { this = "json.loads" } + + override DataFlow::CallCfgNode getACall() { + result = API::moduleImport("json").getMember("loads").getACall() + } + + override DataFlow::CallCfgNode getACallSimple() { none() } + + override DataFlow::ArgumentNode getACallback() { + result = API::moduleImport("json").getMember("loads").getAValueReachableFromSource() + } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[0]" and + output = "ReturnValue.ListElement" and + preservesValue = true + } +} + +// read and store +private class SummarizedCallableReadSecret extends SummarizedCallable { + SummarizedCallableReadSecret() { this = "read_secret" } + + override DataFlow::CallCfgNode getACall() { none() } + + override DataFlow::CallCfgNode getACallSimple() { + result.getFunction().asCfgNode().(NameNode).getId() = this + } + + override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[0].Attribute[secret]" and + output = "ReturnValue" and + preservesValue = true + } +} + +private class SummarizedCallableSetSecret extends SummarizedCallable { + SummarizedCallableSetSecret() { this = "set_secret" } + + override DataFlow::CallCfgNode getACall() { none() } + + override DataFlow::CallCfgNode getACallSimple() { + result.getFunction().asCfgNode().(NameNode).getId() = this + } + + override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[1]" and + output = "Argument[0].Attribute[secret]" and + preservesValue = true + } +} diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py new file mode 100644 index 00000000000..f7affa6036f --- /dev/null +++ b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py @@ -0,0 +1,60 @@ +import sys +import os + +# Simple summary +tainted = identity(tracked) # $ tracked +tainted # $ MISSING: tracked + +# Lambda summary +# I think the missing result is expected because type tracking +# is not allowed to flow back out of a call. +tainted_lambda = apply_lambda(lambda x: x, tracked) # $ tracked +tainted_lambda # $ MISSING: tracked + +# A lambda that directly introduces taint +bad_lambda = apply_lambda(lambda x: tracked, 1) # $ tracked +bad_lambda # $ MISSING: tracked + +# A lambda that breaks the flow +untainted_lambda = apply_lambda(lambda x: 1, tracked) # $ tracked +untainted_lambda + +# Collection summaries +tainted_list = reversed([tracked]) # $ tracked +tl = tainted_list[0] +tl # $ MISSING: tracked + +# Complex summaries +def add_colon(x): + return x + ":" + +tainted_mapped = list_map(add_colon, [tracked]) # $ tracked +tm = tainted_mapped[0] +tm # $ MISSING: tracked + +def explicit_identity(x): + return x + +tainted_mapped_explicit = list_map(explicit_identity, [tracked]) # $ tracked +tainted_mapped_explicit[0] # $ MISSING: tracked + +tainted_mapped_summary = list_map(identity, [tracked]) # $ tracked +tms = tainted_mapped_summary[0] +tms # $ MISSING: tracked + +another_tainted_list = append_to_list([], tracked) # $ tracked +atl = another_tainted_list[0] +atl # $ MISSING: tracked + +from json import loads as json_loads +tainted_resultlist = json_loads(tracked) # $ tracked +tr = tainted_resultlist[0] +tr # $ MISSING: tracked + +x.secret = tracked # $ tracked=secret tracked +r = read_secret(x) # $ tracked=secret MISSING: tracked +r # $ MISSING: tracked + +y # $ MISSING: tracked=secret +set_secret(y, tracked) # $ tracked MISSING: tracked=secret +y.secret # $ MISSING: tracked tracked=secret \ No newline at end of file diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/tracked.expected b/python/ql/test/experimental/dataflow/typetracking-summaries/tracked.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/tracked.ql b/python/ql/test/experimental/dataflow/typetracking-summaries/tracked.ql new file mode 100644 index 00000000000..e5bf62053a0 --- /dev/null +++ b/python/ql/test/experimental/dataflow/typetracking-summaries/tracked.ql @@ -0,0 +1,36 @@ +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TypeTracker +import TestUtilities.InlineExpectationsTest +import semmle.python.ApiGraphs +import TestSummaries + +// ----------------------------------------------------------------------------- +// tracked +// ----------------------------------------------------------------------------- +private DataFlow::TypeTrackingNode tracked(TypeTracker t) { + t.start() and + result.asCfgNode() = any(NameNode n | n.getId() = "tracked") + or + exists(TypeTracker t2 | result = tracked(t2).track(t2, t)) +} + +class TrackedTest extends InlineExpectationsTest { + TrackedTest() { this = "TrackedTest" } + + override string getARelevantTag() { result = "tracked" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(DataFlow::Node e, TypeTracker t | + exists(e.getLocation().getFile().getRelativePath()) and + e.getLocation().getStartLine() > 0 and + tracked(t).flowsTo(e) and + // Module variables have no sensible location, and hence can't be annotated. + not e instanceof DataFlow::ModuleVariableNode and + tag = "tracked" and + location = e.getLocation() and + value = t.getAttr() and + element = e.toString() + ) + } +} From 2daa9577bbbcdf762fb00c96dcd20849245e75b0 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 16 May 2023 14:20:29 +0200 Subject: [PATCH 013/364] ruby/python: implement shared module ruby: - create new shared file `SummaryTypeTracker.qll` - move much logic into the module - instantiate the module - remove old logic, now provided by module python: - clone shared file - instantiate module - use (some of the) steps provided by the module --- config/identical-files.json | 4 + .../new/internal/SummaryTypeTracker.qll | 382 ++++++++++++++++++ .../new/internal/TypeTrackerSpecific.qll | 128 +++++- .../typetracking-summaries/summaries.py | 14 +- .../ruby/typetracking/SummaryTypeTracker.qll | 382 ++++++++++++++++++ .../ruby/typetracking/TypeTrackerSpecific.qll | 370 +++++------------ 6 files changed, 1011 insertions(+), 269 deletions(-) create mode 100644 python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll create mode 100644 ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll diff --git a/config/identical-files.json b/config/identical-files.json index 29fae2d3855..3d84e84dc9c 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -522,6 +522,10 @@ "python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll", "ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll" ], + "SummaryTypeTracker": [ + "python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll", + "ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll" + ], "AccessPathSyntax": [ "csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll", "go/ql/lib/semmle/go/dataflow/internal/AccessPathSyntax.qll", diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll new file mode 100644 index 00000000000..310dec3aadf --- /dev/null +++ b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll @@ -0,0 +1,382 @@ +/** + * Provides the implementation of a summary type tracker, that is type tracking through flow summaries. + * To use this, you must implement the `Input` signature. You can then use the predicates in the `Output` + * signature to implement the predicates of the same names inside `TypeTrackerSpecific.qll`. + */ + +/** The classes and predicates needed to generate a summary type tracker. */ +signature module Input { + // Dataflow nodes + class Node; + + // Content + class TypeTrackerContent; + + class TypeTrackerContentFilter; + + // Relating content and filters + /** + * Gets a content filter to use for a `WithoutContent[content]` step, or has no result if + * the step should be treated as ordinary flow. + * + * `WithoutContent` is often used to perform strong updates on individual collection elements, but for + * type-tracking this is rarely beneficial and quite expensive. However, `WithoutContent` can be quite useful + * for restricting the type of an object, and in these cases we translate it to a filter. + */ + TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content); + + /** + * Gets a content filter to use for a `WithContent[content]` step, or has no result if + * the step cannot be handled by type-tracking. + * + * `WithContent` is often used to perform strong updates on individual collection elements (or rather + * to preserve those that didn't get updated). But for type-tracking this is rarely beneficial and quite expensive. + * However, `WithContent` can be quite useful for restricting the type of an object, and in these cases we translate it to a filter. + */ + TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content); + + // Summaries and their stacks + class SummaryComponent; + + class SummaryComponentStack { + SummaryComponent head(); + } + + /** Gets a singleton stack containing `component`. */ + SummaryComponentStack singleton(SummaryComponent component); + + /** + * Gets the stack obtained by pushing `head` onto `tail`. + */ + SummaryComponentStack push(SummaryComponent component, SummaryComponentStack stack); + + /** Gets a singleton stack representing a return. */ + SummaryComponent return(); + + // Relating content to summaries + /** Gets a summary component for content `c`. */ + SummaryComponent content(TypeTrackerContent contents); + + /** Gets a summary component where data is not allowed to be stored in `c`. */ + SummaryComponent withoutContent(TypeTrackerContent contents); + + /** Gets a summary component where data must be stored in `c`. */ + SummaryComponent withContent(TypeTrackerContent contents); + + // Callables + class SummarizedCallable { + predicate propagatesFlow( + SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue + ); + } + + // Relating nodes to summaries + /** Gets a dataflow node respresenting the argument of `call` indicated by `arg`. */ + Node argumentOf(Node call, SummaryComponent arg); + + /** Gets a dataflow node respresenting the parameter of `callable` indicated by `param`. */ + Node parameterOf(Node callable, SummaryComponent param); + + /** Gets a dataflow node respresenting the return of `callable` indicated by `return`. */ + Node returnOf(Node callable, SummaryComponent return); + + // Specific summary handling + /** Holds if component should be treated as a level step by type tracking. */ + predicate componentLevelStep(SummaryComponent component); + + /** Holds if the given component can't be evaluated by `evaluateSummaryComponentStackLocal`. */ + predicate isNonLocal(SummaryComponent component); + + // Relating callables to nodes + /** Gets a dataflow node respresenting a call to `callable`. */ + Node callTo(SummarizedCallable callable); +} + +/** + * The predicates provided by a summary type tracker. + * These are meant to be used in `TypeTrackerSpecific.qll` + * inside the predicates of the same names. + */ +signature module Output { + /** + * Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. + */ + predicate levelStepNoCall(I::Node nodeFrom, I::Node nodeTo); + + /** + * Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`. + */ + predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content); + + /** + * Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`. + */ + predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content); + + /** + * Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`. + */ + predicate basicLoadStoreStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent, + I::TypeTrackerContent storeContent + ); + + /** + * Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here. + */ + predicate basicWithoutContentStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter + ); + + /** + * Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`. + */ + predicate basicWithContentStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter + ); +} + +/** + * Implementation of the summary type tracker, that is type tracking through flow summaries. + */ +module SummaryFlow implements Output { + pragma[nomagic] + private predicate hasLoadSummary( + I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input, + I::SummaryComponentStack output + ) { + callable.propagatesFlow(I::push(I::content(contents), input), output, true) and + not I::isNonLocal(input.head()) and + not I::isNonLocal(output.head()) + } + + pragma[nomagic] + private predicate hasStoreSummary( + I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input, + I::SummaryComponentStack output + ) { + not I::isNonLocal(input.head()) and + not I::isNonLocal(output.head()) and + ( + callable.propagatesFlow(input, I::push(I::content(contents), output), true) + or + // Allow the input to start with an arbitrary WithoutContent[X]. + // Since type-tracking only tracks one content deep, and we're about to store into another content, + // we're already preventing the input from being in a content. + callable + .propagatesFlow(I::push(I::withoutContent(_), input), + I::push(I::content(contents), output), true) + ) + } + + pragma[nomagic] + private predicate hasLoadStoreSummary( + I::SummarizedCallable callable, I::TypeTrackerContent loadContents, + I::TypeTrackerContent storeContents, I::SummaryComponentStack input, + I::SummaryComponentStack output + ) { + callable + .propagatesFlow(I::push(I::content(loadContents), input), + I::push(I::content(storeContents), output), true) and + not I::isNonLocal(input.head()) and + not I::isNonLocal(output.head()) + } + + pragma[nomagic] + private predicate hasWithoutContentSummary( + I::SummarizedCallable callable, I::TypeTrackerContentFilter filter, + I::SummaryComponentStack input, I::SummaryComponentStack output + ) { + exists(I::TypeTrackerContent content | + callable.propagatesFlow(I::push(I::withoutContent(content), input), output, true) and + filter = I::getFilterFromWithoutContentStep(content) and + not I::isNonLocal(input.head()) and + not I::isNonLocal(output.head()) and + input != output + ) + } + + pragma[nomagic] + private predicate hasWithContentSummary( + I::SummarizedCallable callable, I::TypeTrackerContentFilter filter, + I::SummaryComponentStack input, I::SummaryComponentStack output + ) { + exists(I::TypeTrackerContent content | + callable.propagatesFlow(I::push(I::withContent(content), input), output, true) and + filter = I::getFilterFromWithContentStep(content) and + not I::isNonLocal(input.head()) and + not I::isNonLocal(output.head()) and + input != output + ) + } + + /** + * Gets a data flow I::Node corresponding an argument or return value of `call`, + * as specified by `component`. + */ + bindingset[call, component] + private I::Node evaluateSummaryComponentLocal(I::Node call, I::SummaryComponent component) { + result = I::argumentOf(call, component) + or + component = I::return() and + result = call + } + + /** + * Holds if `callable` is relevant for type-tracking and we therefore want `stack` to + * be evaluated locally at its call sites. + */ + pragma[nomagic] + private predicate dependsOnSummaryComponentStack( + I::SummarizedCallable callable, I::SummaryComponentStack stack + ) { + exists(I::callTo(callable)) and + ( + callable.propagatesFlow(stack, _, true) + or + callable.propagatesFlow(_, stack, true) + or + // include store summaries as they may skip an initial step at the input + hasStoreSummary(callable, _, stack, _) + ) + or + dependsOnSummaryComponentStackCons(callable, _, stack) + } + + pragma[nomagic] + private predicate dependsOnSummaryComponentStackCons( + I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail + ) { + dependsOnSummaryComponentStack(callable, I::push(head, tail)) + } + + pragma[nomagic] + private predicate dependsOnSummaryComponentStackConsLocal( + I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail + ) { + dependsOnSummaryComponentStackCons(callable, head, tail) and + not I::isNonLocal(head) + } + + pragma[nomagic] + private predicate dependsOnSummaryComponentStackLeaf( + I::SummarizedCallable callable, I::SummaryComponent leaf + ) { + dependsOnSummaryComponentStack(callable, I::singleton(leaf)) + } + + /** + * Gets a data flow I::Node corresponding to the local input or output of `call` + * identified by `stack`, if possible. + */ + pragma[nomagic] + private I::Node evaluateSummaryComponentStackLocal( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack stack + ) { + exists(I::SummaryComponent component | + dependsOnSummaryComponentStackLeaf(callable, component) and + stack = I::singleton(component) and + call = I::callTo(callable) and + result = evaluateSummaryComponentLocal(call, component) + ) + or + exists(I::Node prev, I::SummaryComponent head, I::SummaryComponentStack tail | + prev = evaluateSummaryComponentStackLocal(callable, call, tail) and + dependsOnSummaryComponentStackConsLocal(callable, pragma[only_bind_into](head), + pragma[only_bind_out](tail)) and + stack = I::push(pragma[only_bind_out](head), pragma[only_bind_out](tail)) + | + result = I::parameterOf(prev, head) + or + result = I::returnOf(prev, head) + or + I::componentLevelStep(head) and + result = prev + ) + } + + // Implement Output + predicate levelStepNoCall(I::Node nodeFrom, I::Node nodeTo) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + callable.propagatesFlow(input, output, true) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } + + predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + hasLoadSummary(callable, content, pragma[only_bind_into](input), + pragma[only_bind_into](output)) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } + + predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + hasStoreSummary(callable, content, pragma[only_bind_into](input), + pragma[only_bind_into](output)) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } + + predicate basicLoadStoreStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent, + I::TypeTrackerContent storeContent + ) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + hasLoadStoreSummary(callable, loadContent, storeContent, pragma[only_bind_into](input), + pragma[only_bind_into](output)) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } + + predicate basicWithoutContentStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter + ) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + hasWithoutContentSummary(callable, filter, pragma[only_bind_into](input), + pragma[only_bind_into](output)) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } + + predicate basicWithContentStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter + ) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + hasWithContentSummary(callable, filter, pragma[only_bind_into](input), + pragma[only_bind_into](output)) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } +} diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index 9e05b7869c5..81e673dc30b 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -61,7 +61,9 @@ predicate capturedJumpStep(Node nodeFrom, Node nodeTo) { predicate levelStepCall(Node nodeFrom, Node nodeTo) { none() } /** Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. */ -predicate levelStepNoCall(Node nodeFrom, Node nodeTo) { none() } +predicate levelStepNoCall(Node nodeFrom, Node nodeTo) { + TypeTrackerSummaryFlow::levelStepNoCall(nodeFrom, nodeTo) +} /** * Gets the name of a possible piece of content. For Python, this is currently only attribute names, @@ -108,6 +110,12 @@ predicate basicStoreStep(Node nodeFrom, Node nodeTo, string content) { nodeFrom = a.getValue() and nodeTo = a.getObject() ) + or + exists(DataFlowPublic::ContentSet contents | + contents.(DataFlowPublic::AttributeContent).getAttribute() = content + | + TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, contents) + ) } /** @@ -119,13 +127,24 @@ predicate basicLoadStep(Node nodeFrom, Node nodeTo, string content) { nodeFrom = a.getObject() and nodeTo = a ) + or + exists(DataFlowPublic::ContentSet contents | + contents.(DataFlowPublic::AttributeContent).getAttribute() = content + | + TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, contents) + ) } /** * Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`. */ predicate basicLoadStoreStep(Node nodeFrom, Node nodeTo, string loadContent, string storeContent) { - none() + exists(DataFlowPublic::ContentSet loadContents, DataFlowPublic::ContentSet storeContents | + loadContents.(DataFlowPublic::AttributeContent).getAttribute() = loadContent and + storeContents.(DataFlowPublic::AttributeContent).getAttribute() = storeContent + | + TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, loadContents, storeContents) + ) } /** @@ -144,3 +163,108 @@ predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter) class Boolean extends boolean { Boolean() { this = true or this = false } } + +private import SummaryTypeTracker as SummaryTypeTracker +private import semmle.python.dataflow.new.FlowSummary as FlowSummary +private import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowDispatch + +pragma[noinline] +private predicate argumentPositionMatch( + DataFlowPublic::CallCfgNode call, DataFlowPublic::ArgumentNode arg, + DataFlowDispatch::ParameterPosition ppos +) { + exists(DataFlowDispatch::ArgumentPosition apos, DataFlowPrivate::DataFlowCall c | + c.getNode() = call.asCfgNode() and + arg.argumentOf(c, apos) and + DataFlowDispatch::parameterMatch(ppos, apos) + ) +} + +module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { + // Dataflow nodes + class Node = DataFlowPublic::Node; + + // Content + class TypeTrackerContent = DataFlowPublic::ContentSet; + + class TypeTrackerContentFilter = ContentFilter; + + TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content) { none() } + + TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content) { none() } + + // Callables + class SummarizedCallable = FlowSummary::SummarizedCallable; + + // Summaries and their stacks + class SummaryComponent = FlowSummary::SummaryComponent; + + class SummaryComponentStack = FlowSummary::SummaryComponentStack; + + SummaryComponentStack singleton(SummaryComponent component) { + result = FlowSummary::SummaryComponentStack::singleton(component) + } + + SummaryComponentStack push(SummaryComponent component, SummaryComponentStack stack) { + result = FlowSummary::SummaryComponentStack::push(component, stack) + } + + // Relating content to summaries + SummaryComponent content(TypeTrackerContent contents) { + result = FlowSummary::SummaryComponent::content(contents) + } + + SummaryComponent withoutContent(TypeTrackerContent contents) { none() } + + SummaryComponent withContent(TypeTrackerContent contents) { none() } + + SummaryComponent return() { result = FlowSummary::SummaryComponent::return() } + + // Relating nodes to summaries + Node argumentOf(Node call, SummaryComponent arg) { + exists(DataFlowDispatch::ParameterPosition pos | + arg = FlowSummary::SummaryComponent::argument(pos) and + argumentPositionMatch(call, result, pos) + ) + } + + Node parameterOf(Node callable, SummaryComponent param) { + exists( + DataFlowDispatch::ArgumentPosition apos, DataFlowDispatch::ParameterPosition ppos, Parameter p + | + param = FlowSummary::SummaryComponent::parameter(apos) and + DataFlowDispatch::parameterMatch(ppos, apos) and + // pick the SsaNode rather than the CfgNode + result.asVar().getDefinition().(ParameterDefinition).getParameter() = p and + ( + exists(int i | ppos.isPositional(i) | + p = callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getArg(i) + ) + or + exists(string name | ppos.isKeyword(name) | + p = callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getArgByName(name) + ) + ) + ) + } + + Node returnOf(Node callable, SummaryComponent return) { + return = FlowSummary::SummaryComponent::return() and + // result should be return value of callable which should be a lambda + result.asCfgNode() = + callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getAReturnValueFlowNode() + } + + // Specific summary handling + predicate componentLevelStep(SummaryComponent component) { none() } + + pragma[nomagic] + predicate isNonLocal(SummaryComponent component) { + component = FlowSummary::SummaryComponent::content(_) + } + + // Relating callables to nodes + Node callTo(SummarizedCallable callable) { result = callable.getACallSimple() } +} + +module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow; diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py index f7affa6036f..728456cc711 100644 --- a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py +++ b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py @@ -3,7 +3,7 @@ import os # Simple summary tainted = identity(tracked) # $ tracked -tainted # $ MISSING: tracked +tainted # $ tracked # Lambda summary # I think the missing result is expected because type tracking @@ -13,7 +13,7 @@ tainted_lambda # $ MISSING: tracked # A lambda that directly introduces taint bad_lambda = apply_lambda(lambda x: tracked, 1) # $ tracked -bad_lambda # $ MISSING: tracked +bad_lambda # $ tracked # A lambda that breaks the flow untainted_lambda = apply_lambda(lambda x: 1, tracked) # $ tracked @@ -52,9 +52,9 @@ tr = tainted_resultlist[0] tr # $ MISSING: tracked x.secret = tracked # $ tracked=secret tracked -r = read_secret(x) # $ tracked=secret MISSING: tracked -r # $ MISSING: tracked +r = read_secret(x) # $ tracked=secret tracked +r # $ tracked -y # $ MISSING: tracked=secret -set_secret(y, tracked) # $ tracked MISSING: tracked=secret -y.secret # $ MISSING: tracked tracked=secret \ No newline at end of file +y # $ tracked=secret +set_secret(y, tracked) # $ tracked tracked=secret +y.secret # $ tracked tracked=secret \ No newline at end of file diff --git a/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll new file mode 100644 index 00000000000..310dec3aadf --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll @@ -0,0 +1,382 @@ +/** + * Provides the implementation of a summary type tracker, that is type tracking through flow summaries. + * To use this, you must implement the `Input` signature. You can then use the predicates in the `Output` + * signature to implement the predicates of the same names inside `TypeTrackerSpecific.qll`. + */ + +/** The classes and predicates needed to generate a summary type tracker. */ +signature module Input { + // Dataflow nodes + class Node; + + // Content + class TypeTrackerContent; + + class TypeTrackerContentFilter; + + // Relating content and filters + /** + * Gets a content filter to use for a `WithoutContent[content]` step, or has no result if + * the step should be treated as ordinary flow. + * + * `WithoutContent` is often used to perform strong updates on individual collection elements, but for + * type-tracking this is rarely beneficial and quite expensive. However, `WithoutContent` can be quite useful + * for restricting the type of an object, and in these cases we translate it to a filter. + */ + TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content); + + /** + * Gets a content filter to use for a `WithContent[content]` step, or has no result if + * the step cannot be handled by type-tracking. + * + * `WithContent` is often used to perform strong updates on individual collection elements (or rather + * to preserve those that didn't get updated). But for type-tracking this is rarely beneficial and quite expensive. + * However, `WithContent` can be quite useful for restricting the type of an object, and in these cases we translate it to a filter. + */ + TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content); + + // Summaries and their stacks + class SummaryComponent; + + class SummaryComponentStack { + SummaryComponent head(); + } + + /** Gets a singleton stack containing `component`. */ + SummaryComponentStack singleton(SummaryComponent component); + + /** + * Gets the stack obtained by pushing `head` onto `tail`. + */ + SummaryComponentStack push(SummaryComponent component, SummaryComponentStack stack); + + /** Gets a singleton stack representing a return. */ + SummaryComponent return(); + + // Relating content to summaries + /** Gets a summary component for content `c`. */ + SummaryComponent content(TypeTrackerContent contents); + + /** Gets a summary component where data is not allowed to be stored in `c`. */ + SummaryComponent withoutContent(TypeTrackerContent contents); + + /** Gets a summary component where data must be stored in `c`. */ + SummaryComponent withContent(TypeTrackerContent contents); + + // Callables + class SummarizedCallable { + predicate propagatesFlow( + SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue + ); + } + + // Relating nodes to summaries + /** Gets a dataflow node respresenting the argument of `call` indicated by `arg`. */ + Node argumentOf(Node call, SummaryComponent arg); + + /** Gets a dataflow node respresenting the parameter of `callable` indicated by `param`. */ + Node parameterOf(Node callable, SummaryComponent param); + + /** Gets a dataflow node respresenting the return of `callable` indicated by `return`. */ + Node returnOf(Node callable, SummaryComponent return); + + // Specific summary handling + /** Holds if component should be treated as a level step by type tracking. */ + predicate componentLevelStep(SummaryComponent component); + + /** Holds if the given component can't be evaluated by `evaluateSummaryComponentStackLocal`. */ + predicate isNonLocal(SummaryComponent component); + + // Relating callables to nodes + /** Gets a dataflow node respresenting a call to `callable`. */ + Node callTo(SummarizedCallable callable); +} + +/** + * The predicates provided by a summary type tracker. + * These are meant to be used in `TypeTrackerSpecific.qll` + * inside the predicates of the same names. + */ +signature module Output { + /** + * Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. + */ + predicate levelStepNoCall(I::Node nodeFrom, I::Node nodeTo); + + /** + * Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`. + */ + predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content); + + /** + * Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`. + */ + predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content); + + /** + * Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`. + */ + predicate basicLoadStoreStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent, + I::TypeTrackerContent storeContent + ); + + /** + * Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here. + */ + predicate basicWithoutContentStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter + ); + + /** + * Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`. + */ + predicate basicWithContentStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter + ); +} + +/** + * Implementation of the summary type tracker, that is type tracking through flow summaries. + */ +module SummaryFlow implements Output { + pragma[nomagic] + private predicate hasLoadSummary( + I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input, + I::SummaryComponentStack output + ) { + callable.propagatesFlow(I::push(I::content(contents), input), output, true) and + not I::isNonLocal(input.head()) and + not I::isNonLocal(output.head()) + } + + pragma[nomagic] + private predicate hasStoreSummary( + I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input, + I::SummaryComponentStack output + ) { + not I::isNonLocal(input.head()) and + not I::isNonLocal(output.head()) and + ( + callable.propagatesFlow(input, I::push(I::content(contents), output), true) + or + // Allow the input to start with an arbitrary WithoutContent[X]. + // Since type-tracking only tracks one content deep, and we're about to store into another content, + // we're already preventing the input from being in a content. + callable + .propagatesFlow(I::push(I::withoutContent(_), input), + I::push(I::content(contents), output), true) + ) + } + + pragma[nomagic] + private predicate hasLoadStoreSummary( + I::SummarizedCallable callable, I::TypeTrackerContent loadContents, + I::TypeTrackerContent storeContents, I::SummaryComponentStack input, + I::SummaryComponentStack output + ) { + callable + .propagatesFlow(I::push(I::content(loadContents), input), + I::push(I::content(storeContents), output), true) and + not I::isNonLocal(input.head()) and + not I::isNonLocal(output.head()) + } + + pragma[nomagic] + private predicate hasWithoutContentSummary( + I::SummarizedCallable callable, I::TypeTrackerContentFilter filter, + I::SummaryComponentStack input, I::SummaryComponentStack output + ) { + exists(I::TypeTrackerContent content | + callable.propagatesFlow(I::push(I::withoutContent(content), input), output, true) and + filter = I::getFilterFromWithoutContentStep(content) and + not I::isNonLocal(input.head()) and + not I::isNonLocal(output.head()) and + input != output + ) + } + + pragma[nomagic] + private predicate hasWithContentSummary( + I::SummarizedCallable callable, I::TypeTrackerContentFilter filter, + I::SummaryComponentStack input, I::SummaryComponentStack output + ) { + exists(I::TypeTrackerContent content | + callable.propagatesFlow(I::push(I::withContent(content), input), output, true) and + filter = I::getFilterFromWithContentStep(content) and + not I::isNonLocal(input.head()) and + not I::isNonLocal(output.head()) and + input != output + ) + } + + /** + * Gets a data flow I::Node corresponding an argument or return value of `call`, + * as specified by `component`. + */ + bindingset[call, component] + private I::Node evaluateSummaryComponentLocal(I::Node call, I::SummaryComponent component) { + result = I::argumentOf(call, component) + or + component = I::return() and + result = call + } + + /** + * Holds if `callable` is relevant for type-tracking and we therefore want `stack` to + * be evaluated locally at its call sites. + */ + pragma[nomagic] + private predicate dependsOnSummaryComponentStack( + I::SummarizedCallable callable, I::SummaryComponentStack stack + ) { + exists(I::callTo(callable)) and + ( + callable.propagatesFlow(stack, _, true) + or + callable.propagatesFlow(_, stack, true) + or + // include store summaries as they may skip an initial step at the input + hasStoreSummary(callable, _, stack, _) + ) + or + dependsOnSummaryComponentStackCons(callable, _, stack) + } + + pragma[nomagic] + private predicate dependsOnSummaryComponentStackCons( + I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail + ) { + dependsOnSummaryComponentStack(callable, I::push(head, tail)) + } + + pragma[nomagic] + private predicate dependsOnSummaryComponentStackConsLocal( + I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail + ) { + dependsOnSummaryComponentStackCons(callable, head, tail) and + not I::isNonLocal(head) + } + + pragma[nomagic] + private predicate dependsOnSummaryComponentStackLeaf( + I::SummarizedCallable callable, I::SummaryComponent leaf + ) { + dependsOnSummaryComponentStack(callable, I::singleton(leaf)) + } + + /** + * Gets a data flow I::Node corresponding to the local input or output of `call` + * identified by `stack`, if possible. + */ + pragma[nomagic] + private I::Node evaluateSummaryComponentStackLocal( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack stack + ) { + exists(I::SummaryComponent component | + dependsOnSummaryComponentStackLeaf(callable, component) and + stack = I::singleton(component) and + call = I::callTo(callable) and + result = evaluateSummaryComponentLocal(call, component) + ) + or + exists(I::Node prev, I::SummaryComponent head, I::SummaryComponentStack tail | + prev = evaluateSummaryComponentStackLocal(callable, call, tail) and + dependsOnSummaryComponentStackConsLocal(callable, pragma[only_bind_into](head), + pragma[only_bind_out](tail)) and + stack = I::push(pragma[only_bind_out](head), pragma[only_bind_out](tail)) + | + result = I::parameterOf(prev, head) + or + result = I::returnOf(prev, head) + or + I::componentLevelStep(head) and + result = prev + ) + } + + // Implement Output + predicate levelStepNoCall(I::Node nodeFrom, I::Node nodeTo) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + callable.propagatesFlow(input, output, true) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } + + predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + hasLoadSummary(callable, content, pragma[only_bind_into](input), + pragma[only_bind_into](output)) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } + + predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + hasStoreSummary(callable, content, pragma[only_bind_into](input), + pragma[only_bind_into](output)) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } + + predicate basicLoadStoreStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent, + I::TypeTrackerContent storeContent + ) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + hasLoadStoreSummary(callable, loadContent, storeContent, pragma[only_bind_into](input), + pragma[only_bind_into](output)) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } + + predicate basicWithoutContentStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter + ) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + hasWithoutContentSummary(callable, filter, pragma[only_bind_into](input), + pragma[only_bind_into](output)) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } + + predicate basicWithContentStep( + I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter + ) { + exists( + I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input, + I::SummaryComponentStack output + | + hasWithContentSummary(callable, filter, pragma[only_bind_into](input), + pragma[only_bind_into](output)) and + call = I::callTo(callable) and + nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and + nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) + ) + } +} diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll index 55ec26258d6..4f17302e72b 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll @@ -112,15 +112,7 @@ predicate levelStepCall(Node nodeFrom, Node nodeTo) { /** Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. */ pragma[nomagic] predicate levelStepNoCall(Node nodeFrom, Node nodeTo) { - exists( - SummarizedCallable callable, DataFlowPublic::CallNode call, SummaryComponentStack input, - SummaryComponentStack output - | - callable.propagatesFlow(input, output, true) and - call.asExpr().getExpr() = callable.getACallSimple() and - nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and - nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) - ) + TypeTrackerSummaryFlow::levelStepNoCall(nodeFrom, nodeTo) or localFieldStep(nodeFrom, nodeTo) } @@ -290,16 +282,7 @@ predicate returnStep(Node nodeFrom, Node nodeTo) { predicate basicStoreStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet contents) { storeStepIntoSourceNode(nodeFrom, nodeTo, contents) or - exists( - SummarizedCallable callable, DataFlowPublic::CallNode call, SummaryComponentStack input, - SummaryComponentStack output - | - hasStoreSummary(callable, contents, pragma[only_bind_into](input), - pragma[only_bind_into](output)) and - call.asExpr().getExpr() = callable.getACallSimple() and - nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and - nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) - ) + TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, contents) } /** @@ -333,15 +316,7 @@ predicate basicLoadStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet content nodeTo.asExpr() = call ) or - exists( - SummarizedCallable callable, DataFlowPublic::CallNode call, SummaryComponentStack input, - SummaryComponentStack output - | - hasLoadSummary(callable, contents, pragma[only_bind_into](input), pragma[only_bind_into](output)) and - call.asExpr().getExpr() = callable.getACallSimple() and - nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and - nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) - ) + TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, contents) } /** @@ -350,48 +325,21 @@ predicate basicLoadStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet content predicate basicLoadStoreStep( Node nodeFrom, Node nodeTo, DataFlow::ContentSet loadContent, DataFlow::ContentSet storeContent ) { - exists( - SummarizedCallable callable, DataFlowPublic::CallNode call, SummaryComponentStack input, - SummaryComponentStack output - | - hasLoadStoreSummary(callable, loadContent, storeContent, pragma[only_bind_into](input), - pragma[only_bind_into](output)) and - call.asExpr().getExpr() = callable.getACallSimple() and - nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and - nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) - ) + TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent) } /** * Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here. */ predicate basicWithoutContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter) { - exists( - SummarizedCallable callable, DataFlowPublic::CallNode call, SummaryComponentStack input, - SummaryComponentStack output - | - hasWithoutContentSummary(callable, filter, pragma[only_bind_into](input), - pragma[only_bind_into](output)) and - call.asExpr().getExpr() = callable.getACallSimple() and - nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and - nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) - ) + TypeTrackerSummaryFlow::basicWithoutContentStep(nodeFrom, nodeTo, filter) } /** * Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`. */ predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter) { - exists( - SummarizedCallable callable, DataFlowPublic::CallNode call, SummaryComponentStack input, - SummaryComponentStack output - | - hasWithContentSummary(callable, filter, pragma[only_bind_into](input), - pragma[only_bind_into](output)) and - call.asExpr().getExpr() = callable.getACallSimple() and - nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and - nodeTo = evaluateSummaryComponentStackLocal(callable, call, output) - ) + TypeTrackerSummaryFlow::basicWithContentStep(nodeFrom, nodeTo, filter) } /** @@ -403,121 +351,6 @@ class Boolean extends boolean { private import SummaryComponentStack -pragma[nomagic] -private predicate hasStoreSummary( - SummarizedCallable callable, DataFlow::ContentSet contents, SummaryComponentStack input, - SummaryComponentStack output -) { - not isNonLocal(input.head()) and - not isNonLocal(output.head()) and - ( - callable.propagatesFlow(input, push(SummaryComponent::content(contents), output), true) - or - // Allow the input to start with an arbitrary WithoutContent[X]. - // Since type-tracking only tracks one content deep, and we're about to store into another content, - // we're already preventing the input from being in a content. - callable - .propagatesFlow(push(SummaryComponent::withoutContent(_), input), - push(SummaryComponent::content(contents), output), true) - ) -} - -pragma[nomagic] -private predicate hasLoadSummary( - SummarizedCallable callable, DataFlow::ContentSet contents, SummaryComponentStack input, - SummaryComponentStack output -) { - callable.propagatesFlow(push(SummaryComponent::content(contents), input), output, true) and - not isNonLocal(input.head()) and - not isNonLocal(output.head()) -} - -pragma[nomagic] -private predicate hasLoadStoreSummary( - SummarizedCallable callable, DataFlow::ContentSet loadContents, - DataFlow::ContentSet storeContents, SummaryComponentStack input, SummaryComponentStack output -) { - callable - .propagatesFlow(push(SummaryComponent::content(loadContents), input), - push(SummaryComponent::content(storeContents), output), true) and - not isNonLocal(input.head()) and - not isNonLocal(output.head()) -} - -/** - * Gets a content filter to use for a `WithoutContent[content]` step, or has no result if - * the step should be treated as ordinary flow. - * - * `WithoutContent` is often used to perform strong updates on individual collection elements, but for - * type-tracking this is rarely beneficial and quite expensive. However, `WithoutContent` can be quite useful - * for restricting the type of an object, and in these cases we translate it to a filter. - */ -private ContentFilter getFilterFromWithoutContentStep(DataFlow::ContentSet content) { - ( - content.isAnyElement() - or - content.isElementLowerBoundOrUnknown(_) - or - content.isElementOfTypeOrUnknown(_) - or - content.isSingleton(any(DataFlow::Content::UnknownElementContent c)) - ) and - result = MkElementFilter() -} - -pragma[nomagic] -private predicate hasWithoutContentSummary( - SummarizedCallable callable, ContentFilter filter, SummaryComponentStack input, - SummaryComponentStack output -) { - exists(DataFlow::ContentSet content | - callable.propagatesFlow(push(SummaryComponent::withoutContent(content), input), output, true) and - filter = getFilterFromWithoutContentStep(content) and - not isNonLocal(input.head()) and - not isNonLocal(output.head()) and - input != output - ) -} - -/** - * Gets a content filter to use for a `WithContent[content]` step, or has no result if - * the step cannot be handled by type-tracking. - * - * `WithContent` is often used to perform strong updates on individual collection elements (or rather - * to preserve those that didn't get updated). But for type-tracking this is rarely beneficial and quite expensive. - * However, `WithContent` can be quite useful for restricting the type of an object, and in these cases we translate it to a filter. - */ -private ContentFilter getFilterFromWithContentStep(DataFlow::ContentSet content) { - ( - content.isAnyElement() - or - content.isElementLowerBound(_) - or - content.isElementLowerBoundOrUnknown(_) - or - content.isElementOfType(_) - or - content.isElementOfTypeOrUnknown(_) - or - content.isSingleton(any(DataFlow::Content::ElementContent c)) - ) and - result = MkElementFilter() -} - -pragma[nomagic] -private predicate hasWithContentSummary( - SummarizedCallable callable, ContentFilter filter, SummaryComponentStack input, - SummaryComponentStack output -) { - exists(DataFlow::ContentSet content | - callable.propagatesFlow(push(SummaryComponent::withContent(content), input), output, true) and - filter = getFilterFromWithContentStep(content) and - not isNonLocal(input.head()) and - not isNonLocal(output.head()) and - input != output - ) -} - /** * Holds if the given component can't be evaluated by `evaluateSummaryComponentStackLocal`. */ @@ -528,112 +361,129 @@ predicate isNonLocal(SummaryComponent component) { component = SC::withContent(_) } -/** - * Gets a data flow node corresponding an argument or return value of `call`, - * as specified by `component`. - */ -bindingset[call, component] -private DataFlow::Node evaluateSummaryComponentLocal( - DataFlow::CallNode call, SummaryComponent component -) { - exists(DataFlowDispatch::ParameterPosition pos | - component = SummaryComponent::argument(pos) and - argumentPositionMatch(call.asExpr(), result, pos) - ) - or - component = SummaryComponent::return() and - result = call -} +private import SummaryTypeTracker as SummaryTypeTracker +private import codeql.ruby.dataflow.FlowSummary as FlowSummary -/** - * Holds if `callable` is relevant for type-tracking and we therefore want `stack` to - * be evaluated locally at its call sites. - */ -pragma[nomagic] -private predicate dependsOnSummaryComponentStack( - SummarizedCallable callable, SummaryComponentStack stack -) { - exists(callable.getACallSimple()) and - ( - callable.propagatesFlow(stack, _, true) - or - callable.propagatesFlow(_, stack, true) - or - // include store summaries as they may skip an initial step at the input - hasStoreSummary(callable, _, stack, _) - ) - or - dependsOnSummaryComponentStackCons(callable, _, stack) -} +module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { + // Dataflow nodes + class Node = DataFlow::Node; -pragma[nomagic] -private predicate dependsOnSummaryComponentStackCons( - SummarizedCallable callable, SummaryComponent head, SummaryComponentStack tail -) { - dependsOnSummaryComponentStack(callable, SCS::push(head, tail)) -} + // Content + class TypeTrackerContent = DataFlowPublic::ContentSet; -pragma[nomagic] -private predicate dependsOnSummaryComponentStackConsLocal( - SummarizedCallable callable, SummaryComponent head, SummaryComponentStack tail -) { - dependsOnSummaryComponentStackCons(callable, head, tail) and - not isNonLocal(head) -} + class TypeTrackerContentFilter = ContentFilter; -pragma[nomagic] -private predicate dependsOnSummaryComponentStackLeaf( - SummarizedCallable callable, SummaryComponent leaf -) { - dependsOnSummaryComponentStack(callable, SCS::singleton(leaf)) -} + TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content) { + ( + content.isAnyElement() + or + content.isElementLowerBoundOrUnknown(_) + or + content.isElementOfTypeOrUnknown(_) + or + content.isSingleton(any(DataFlow::Content::UnknownElementContent c)) + ) and + result = MkElementFilter() + } -/** - * Gets a data flow node corresponding to the local input or output of `call` - * identified by `stack`, if possible. - */ -pragma[nomagic] -private DataFlow::Node evaluateSummaryComponentStackLocal( - SummarizedCallable callable, DataFlow::CallNode call, SummaryComponentStack stack -) { - exists(SummaryComponent component | - dependsOnSummaryComponentStackLeaf(callable, component) and - stack = SCS::singleton(component) and - call.asExpr().getExpr() = callable.getACallSimple() and - result = evaluateSummaryComponentLocal(call, component) - ) - or - exists(DataFlow::Node prev, SummaryComponent head, SummaryComponentStack tail | - prev = evaluateSummaryComponentStackLocal(callable, call, tail) and - dependsOnSummaryComponentStackConsLocal(callable, pragma[only_bind_into](head), - pragma[only_bind_out](tail)) and - stack = SCS::push(pragma[only_bind_out](head), pragma[only_bind_out](tail)) - | + TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content) { + ( + content.isAnyElement() + or + content.isElementLowerBound(_) + or + content.isElementLowerBoundOrUnknown(_) + or + content.isElementOfType(_) + or + content.isElementOfTypeOrUnknown(_) + or + content.isSingleton(any(DataFlow::Content::ElementContent c)) + ) and + result = MkElementFilter() + } + + // Summaries and their stacks + class SummaryComponent = FlowSummary::SummaryComponent; + + class SummaryComponentStack = FlowSummary::SummaryComponentStack; + + SummaryComponentStack singleton(SummaryComponent component) { + result = FlowSummary::SummaryComponentStack::singleton(component) + } + + SummaryComponentStack push(SummaryComponent component, SummaryComponentStack stack) { + result = FlowSummary::SummaryComponentStack::push(component, stack) + } + + // Relating content to summaries + SummaryComponent content(TypeTrackerContent contents) { + result = FlowSummary::SummaryComponent::content(contents) + } + + SummaryComponent withoutContent(TypeTrackerContent contents) { + result = FlowSummary::SummaryComponent::withoutContent(contents) + } + + SummaryComponent withContent(TypeTrackerContent contents) { + result = FlowSummary::SummaryComponent::withContent(contents) + } + + SummaryComponent return() { result = FlowSummary::SummaryComponent::return() } + + // Callables + class SummarizedCallable = FlowSummary::SummarizedCallable; + + // Relating nodes to summaries + Node argumentOf(Node call, SummaryComponent arg) { + exists(DataFlowDispatch::ParameterPosition pos | + arg = SummaryComponent::argument(pos) and + argumentPositionMatch(call.asExpr(), result, pos) + ) + } + + Node parameterOf(Node callable, SummaryComponent param) { exists( DataFlowDispatch::ArgumentPosition apos, DataFlowDispatch::ParameterPosition ppos, DataFlowPrivate::ParameterNodeImpl p | - head = SummaryComponent::parameter(apos) and + param = SummaryComponent::parameter(apos) and DataFlowDispatch::parameterMatch(ppos, apos) and - p.isSourceParameterOf(prev.asExpr().getExpr(), ppos) and + p.isSourceParameterOf(callable.asExpr().getExpr(), ppos) and // We need to include both `p` and the SSA definition for `p`, since in type-tracking // the step from `p` to the SSA definition is considered a call step. result = [p.(DataFlow::Node), DataFlowPrivate::LocalFlow::getParameterDefNode(p.getParameter())] ) - or + } + + Node returnOf(Node callable, SummaryComponent return) { exists(DataFlowPrivate::SynthReturnNode ret | - head = SummaryComponent::return() and - ret.getCfgScope() = prev.asExpr().getExpr() and + return = SummaryComponent::return() and + ret.getCfgScope() = callable.asExpr().getExpr() and // We need to include both `ret` and `ret.getAnInput()`, since in type-tracking // the step from `ret.getAnInput()` to `ret` is considered a return step. result = [ret.(DataFlow::Node), ret.getAnInput()] ) - or - exists(DataFlow::ContentSet content | - head = SummaryComponent::withoutContent(content) and - not exists(getFilterFromWithoutContentStep(content)) and - result = prev + } + + // Specific summary handling + predicate componentLevelStep(SummaryComponent component) { + exists(TypeTrackerContent content | + component = SummaryComponent::withoutContent(content) and + not exists(getFilterFromWithoutContentStep(content)) ) - ) + } + + pragma[nomagic] + predicate isNonLocal(SummaryComponent component) { + component = SC::content(_) + or + component = SC::withContent(_) + } + + // Relating callables to nodes + Node callTo(SummarizedCallable callable) { result.asExpr().getExpr() = callable.getACallSimple() } } + +module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow; From 820b5f235eba6c92251dde37ad2f052092648c75 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 30 May 2023 13:36:10 +0200 Subject: [PATCH 014/364] python: add change note --- .../2023-05-30-typetracking-via-flow-summaries.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/lib/change-notes/2023-05-30-typetracking-via-flow-summaries.md diff --git a/python/ql/lib/change-notes/2023-05-30-typetracking-via-flow-summaries.md b/python/ql/lib/change-notes/2023-05-30-typetracking-via-flow-summaries.md new file mode 100644 index 00000000000..11c01629987 --- /dev/null +++ b/python/ql/lib/change-notes/2023-05-30-typetracking-via-flow-summaries.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Type tracking is now aware of flow summaries. This leads to a richer API graph, and may lead to more results in some queries. From e7e0cf5cb3f21f04e45a4373141e0900ed0993ed Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 16 May 2023 14:45:59 +0100 Subject: [PATCH 015/364] ruby: add Rack::ResponseNode class --- .../codeql/ruby/dataflow/internal/DataFlowPublic.qll | 11 ++++++++--- ruby/ql/lib/codeql/ruby/frameworks/Rack.qll | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll index 9d668e0b300..c076d6d6698 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll @@ -1279,13 +1279,18 @@ class HashLiteralNode extends LocalSourceNode, ExprNode { * into calls to `Array.[]`, so this includes both desugared calls as well as * explicit calls. */ -class ArrayLiteralNode extends LocalSourceNode, ExprNode { - ArrayLiteralNode() { super.getExprNode() instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode } +class ArrayLiteralNode extends LocalSourceNode, CallNode { + private CfgNodes::ExprNodes::ArrayLiteralCfgNode arrayNode; + + ArrayLiteralNode() { super.getExprNode() = arrayNode } /** * Gets an element of the array. */ - Node getAnElement() { result = this.(CallNode).getPositionalArgument(_) } + Node getAnElement() { result = this.getElement(_) } + + /** Gets the `i`th element of the array. */ + Node getElement(int i) { result = this.getPositionalArgument(i) } } /** diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll index 693cd4c197c..b5a6242c35a 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll @@ -30,14 +30,14 @@ module Rack { DataFlow::ParameterNode getEnv() { result = call.getParameter(0) } } - private predicate isRackResponse(DataFlow::Node r) { + class ResponseNode extends DataFlow::ArrayLiteralNode { // [status, headers, body] - r.asExpr().(ArrayLiteralCfgNode).getNumberOfArguments() = 3 + ResponseNode() { this.getNumberOfArguments() = 3 } } private DataFlow::LocalSourceNode trackRackResponse(TypeTracker t) { t.start() and - isRackResponse(result) + result instanceof ResponseNode or exists(TypeTracker t2 | result = trackRackResponse(t2).track(t2, t)) } From c87c26687190a898edd0b65f5eb6acde8a2a87ab Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 16 May 2023 14:47:36 +0100 Subject: [PATCH 016/364] ruby: add Rack::ResponseNode#getAStatusCode --- ruby/ql/lib/codeql/ruby/frameworks/Rack.qll | 16 ++++++++++++++++ .../library-tests/frameworks/rack/Rack.expected | 15 +++++++++++---- .../test/library-tests/frameworks/rack/Rack.ql | 4 ++++ .../test/library-tests/frameworks/rack/rack.rb | 6 +++++- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll index b5a6242c35a..ec3673207ac 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll @@ -30,9 +30,25 @@ module Rack { DataFlow::ParameterNode getEnv() { result = call.getParameter(0) } } + private DataFlow::LocalSourceNode trackStatusCode(TypeTracker t, int i) { + t.start() and + result.getConstantValue().isInt(i) + or + exists(TypeTracker t2 | result = trackStatusCode(t2, i).track(t2, t)) + } + + private DataFlow::Node trackStatusCode(int i) { + trackStatusCode(TypeTracker::end(), i).flowsTo(result) + } + class ResponseNode extends DataFlow::ArrayLiteralNode { // [status, headers, body] ResponseNode() { this.getNumberOfArguments() = 3 } + + /** + * Gets an HTTP status code that may be returned in this response. + */ + int getAStatusCode() { this.getElement(0) = trackStatusCode(result) } } private DataFlow::LocalSourceNode trackRackResponse(TypeTracker t) { diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.expected b/ruby/ql/test/library-tests/frameworks/rack/Rack.expected index 5613aabd7a4..db76f4545b6 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.expected +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.expected @@ -1,4 +1,11 @@ -| rack.rb:1:1:5:3 | HelloWorld | rack.rb:2:12:2:14 | env | -| rack.rb:7:1:16:3 | Proxy | rack.rb:12:12:12:18 | the_env | -| rack.rb:18:1:31:3 | Logger | rack.rb:24:12:24:14 | env | -| rack.rb:45:1:61:3 | Baz | rack.rb:46:12:46:14 | env | +rackApps +| rack.rb:1:1:9:3 | HelloWorld | rack.rb:2:12:2:14 | env | +| rack.rb:11:1:20:3 | Proxy | rack.rb:16:12:16:18 | the_env | +| rack.rb:22:1:35:3 | Logger | rack.rb:28:12:28:14 | env | +| rack.rb:49:1:65:3 | Baz | rack.rb:50:12:50:14 | env | +rackResponseStatusCodes +| rack.rb:7:5:7:63 | call to [] | 200 | +| rack.rb:7:5:7:63 | call to [] | 500 | +| rack.rb:39:5:39:13 | call to [] | 1 | +| rack.rb:56:7:56:22 | call to [] | 200 | +| rack.rb:63:5:63:21 | call to [] | 400 | diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql index 560b81c3839..25c8303853d 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql @@ -2,3 +2,7 @@ private import codeql.ruby.frameworks.Rack private import codeql.ruby.DataFlow query predicate rackApps(Rack::AppCandidate c, DataFlow::ParameterNode env) { env = c.getEnv() } + +query predicate rackResponseStatusCodes(Rack::ResponseNode resp, int status) { + status = resp.getAStatusCode() +} diff --git a/ruby/ql/test/library-tests/frameworks/rack/rack.rb b/ruby/ql/test/library-tests/frameworks/rack/rack.rb index 03955455787..c3b7729812b 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/rack.rb +++ b/ruby/ql/test/library-tests/frameworks/rack/rack.rb @@ -1,6 +1,10 @@ class HelloWorld def call(env) - [200, {'Content-Type' => 'text/plain'}, ['Hello World']] + status = 200 + if something_goes_wrong(env) + status = 500 + end + [status, {'Content-Type' => 'text/plain'}, ['Hello World']] end end From f8d2cbbe7932c11bd97c7bbd7fb064427cc8f601 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 16 May 2023 16:40:41 +0100 Subject: [PATCH 017/364] ruby: rack responses implement are HTTP responses --- ruby/ql/lib/codeql/ruby/frameworks/Rack.qll | 44 +++++++++++++------ .../frameworks/rack/Rack.expected | 3 +- .../library-tests/frameworks/rack/Rack.ql | 6 ++- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll index ec3673207ac..503af8e8533 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll @@ -2,6 +2,7 @@ * Provides modeling for the Rack library. */ +private import codeql.ruby.Concepts private import codeql.ruby.controlflow.CfgNodes::ExprNodes private import codeql.ruby.DataFlow private import codeql.ruby.typetracking.TypeTracker @@ -17,48 +18,63 @@ module Rack { */ class AppCandidate extends DataFlow::ClassNode { private DataFlow::MethodNode call; + private PotentialResponseNode resp; AppCandidate() { call = this.getInstanceMethod("call") and call.getNumberOfParameters() = 1 and - call.getReturn() = trackRackResponse() + call.getReturn() = trackRackResponse(resp) } /** * Gets the environment of the request, which is the lone parameter to the `call` method. */ DataFlow::ParameterNode getEnv() { result = call.getParameter(0) } + + /** Gets the response returned from the request. */ + PotentialResponseNode getResponse() { result = resp } } - private DataFlow::LocalSourceNode trackStatusCode(TypeTracker t, int i) { + private DataFlow::LocalSourceNode trackInt(TypeTracker t, int i) { t.start() and result.getConstantValue().isInt(i) or - exists(TypeTracker t2 | result = trackStatusCode(t2, i).track(t2, t)) + exists(TypeTracker t2 | result = trackInt(t2, i).track(t2, t)) } - private DataFlow::Node trackStatusCode(int i) { - trackStatusCode(TypeTracker::end(), i).flowsTo(result) - } + private DataFlow::Node trackInt(int i) { trackInt(TypeTracker::end(), i).flowsTo(result) } - class ResponseNode extends DataFlow::ArrayLiteralNode { + private class PotentialResponseNode extends DataFlow::ArrayLiteralNode { // [status, headers, body] - ResponseNode() { this.getNumberOfArguments() = 3 } + PotentialResponseNode() { this.getNumberOfArguments() = 3 } /** * Gets an HTTP status code that may be returned in this response. */ - int getAStatusCode() { this.getElement(0) = trackStatusCode(result) } + int getAStatusCode() { this.getElement(0) = trackInt(result) } } - private DataFlow::LocalSourceNode trackRackResponse(TypeTracker t) { + private DataFlow::LocalSourceNode trackRackResponse(TypeTracker t, PotentialResponseNode n) { t.start() and - result instanceof ResponseNode + result = n or - exists(TypeTracker t2 | result = trackRackResponse(t2).track(t2, t)) + exists(TypeTracker t2 | result = trackRackResponse(t2, n).track(t2, t)) } - private DataFlow::Node trackRackResponse() { - trackRackResponse(TypeTracker::end()).flowsTo(result) + private DataFlow::Node trackRackResponse(PotentialResponseNode n) { + trackRackResponse(TypeTracker::end(), n).flowsTo(result) + } + + /** A `DataFlow::Node` returned from a rack request. */ + class ResponseNode extends PotentialResponseNode, Http::Server::HttpResponse::Range { + ResponseNode() { this = any(AppCandidate app).getResponse() } + + override DataFlow::Node getBody() { result = this.getElement(2) } + + // TODO + override DataFlow::Node getMimetypeOrContentTypeArg() { none() } + + // TODO + override string getMimetypeDefault() { none() } } } diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.expected b/ruby/ql/test/library-tests/frameworks/rack/Rack.expected index db76f4545b6..23fec9a8266 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.expected +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.expected @@ -6,6 +6,7 @@ rackApps rackResponseStatusCodes | rack.rb:7:5:7:63 | call to [] | 200 | | rack.rb:7:5:7:63 | call to [] | 500 | -| rack.rb:39:5:39:13 | call to [] | 1 | +| rack.rb:18:5:18:27 | call to [] | | +| rack.rb:33:5:33:26 | call to [] | | | rack.rb:56:7:56:22 | call to [] | 200 | | rack.rb:63:5:63:21 | call to [] | 400 | diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql index 25c8303853d..6e18162a5e1 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql @@ -3,6 +3,8 @@ private import codeql.ruby.DataFlow query predicate rackApps(Rack::AppCandidate c, DataFlow::ParameterNode env) { env = c.getEnv() } -query predicate rackResponseStatusCodes(Rack::ResponseNode resp, int status) { - status = resp.getAStatusCode() +query predicate rackResponseStatusCodes(Rack::ResponseNode resp, string status) { + if exists(resp.getAStatusCode()) + then status = resp.getAStatusCode().toString() + else status = "" } From c3ab867595b79920a4ccbcfd183864831c6aa114 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Mon, 22 May 2023 09:32:40 +0100 Subject: [PATCH 018/364] ruby: start restructuring rack --- ruby/ql/lib/codeql/ruby/frameworks/Rack.qll | 76 +- .../lib/codeql/ruby/frameworks/rack/Rack.qll | 120 ++ .../frameworks/rack/internal/MimeTypes.qll | 1285 +++++++++++++++++ .../library-tests/frameworks/rack/Rack.ql | 7 + .../library-tests/frameworks/rack/rack.rb | 4 +- 5 files changed, 1416 insertions(+), 76 deletions(-) create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/rack/internal/MimeTypes.qll diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll index 503af8e8533..ba969ae4c45 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll @@ -1,80 +1,6 @@ -/** - * Provides modeling for the Rack library. - */ - -private import codeql.ruby.Concepts -private import codeql.ruby.controlflow.CfgNodes::ExprNodes -private import codeql.ruby.DataFlow -private import codeql.ruby.typetracking.TypeTracker - /** * Provides modeling for the Rack library. */ module Rack { - /** - * A class that may be a rack application. - * This is a class that has a `call` method that takes a single argument - * (traditionally called `env`) and returns a rack-compatible response. - */ - class AppCandidate extends DataFlow::ClassNode { - private DataFlow::MethodNode call; - private PotentialResponseNode resp; - - AppCandidate() { - call = this.getInstanceMethod("call") and - call.getNumberOfParameters() = 1 and - call.getReturn() = trackRackResponse(resp) - } - - /** - * Gets the environment of the request, which is the lone parameter to the `call` method. - */ - DataFlow::ParameterNode getEnv() { result = call.getParameter(0) } - - /** Gets the response returned from the request. */ - PotentialResponseNode getResponse() { result = resp } - } - - private DataFlow::LocalSourceNode trackInt(TypeTracker t, int i) { - t.start() and - result.getConstantValue().isInt(i) - or - exists(TypeTracker t2 | result = trackInt(t2, i).track(t2, t)) - } - - private DataFlow::Node trackInt(int i) { trackInt(TypeTracker::end(), i).flowsTo(result) } - - private class PotentialResponseNode extends DataFlow::ArrayLiteralNode { - // [status, headers, body] - PotentialResponseNode() { this.getNumberOfArguments() = 3 } - - /** - * Gets an HTTP status code that may be returned in this response. - */ - int getAStatusCode() { this.getElement(0) = trackInt(result) } - } - - private DataFlow::LocalSourceNode trackRackResponse(TypeTracker t, PotentialResponseNode n) { - t.start() and - result = n - or - exists(TypeTracker t2 | result = trackRackResponse(t2, n).track(t2, t)) - } - - private DataFlow::Node trackRackResponse(PotentialResponseNode n) { - trackRackResponse(TypeTracker::end(), n).flowsTo(result) - } - - /** A `DataFlow::Node` returned from a rack request. */ - class ResponseNode extends PotentialResponseNode, Http::Server::HttpResponse::Range { - ResponseNode() { this = any(AppCandidate app).getResponse() } - - override DataFlow::Node getBody() { result = this.getElement(2) } - - // TODO - override DataFlow::Node getMimetypeOrContentTypeArg() { none() } - - // TODO - override string getMimetypeDefault() { none() } - } + import rack.Rack } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll new file mode 100644 index 00000000000..b570f276c51 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll @@ -0,0 +1,120 @@ +/** + * Provides modeling for the Rack library. + */ + +private import codeql.ruby.AST +private import codeql.ruby.ApiGraphs +private import codeql.ruby.Concepts +private import codeql.ruby.controlflow.CfgNodes::ExprNodes +private import codeql.ruby.DataFlow +private import codeql.ruby.typetracking.TypeTracker +private import internal.MimeTypes + +/** + * A class that may be a rack application. + * This is a class that has a `call` method that takes a single argument + * (traditionally called `env`) and returns a rack-compatible response. + */ +class AppCandidate extends DataFlow::ClassNode { + private DataFlow::MethodNode call; + private PotentialResponseNode resp; + + AppCandidate() { + call = this.getInstanceMethod("call") and + call.getNumberOfParameters() = 1 and + call.getReturn() = trackRackResponse(resp) + } + + /** + * Gets the environment of the request, which is the lone parameter to the `call` method. + */ + DataFlow::ParameterNode getEnv() { result = call.getParameter(0) } + + /** Gets the response returned from the request. */ + PotentialResponseNode getResponse() { result = resp } +} + +private DataFlow::LocalSourceNode trackInt(TypeTracker t, int i) { + t.start() and + result.getConstantValue().isInt(i) + or + exists(TypeTracker t2 | result = trackInt(t2, i).track(t2, t)) +} + +private DataFlow::Node trackInt(int i) { trackInt(TypeTracker::end(), i).flowsTo(result) } + +private class PotentialResponseNode extends DataFlow::ArrayLiteralNode { + // [status, headers, body] + PotentialResponseNode() { this.getNumberOfArguments() = 3 } + + /** + * Gets an HTTP status code that may be returned in this response. + */ + int getAStatusCode() { this.getElement(0) = trackInt(result) } + + /** Gets the headers returned with this response. */ + DataFlow::Node getHeaders() { result = this.getElement(1) } + + /** Gets the body of this response. */ + DataFlow::Node getBody() { result = this.getElement(2) } +} + +private DataFlow::LocalSourceNode trackRackResponse(TypeTracker t, PotentialResponseNode n) { + t.start() and + result = n + or + exists(TypeTracker t2 | result = trackRackResponse(t2, n).track(t2, t)) +} + +private DataFlow::Node trackRackResponse(PotentialResponseNode n) { + trackRackResponse(TypeTracker::end(), n).flowsTo(result) +} + +class MimetypeCall extends DataFlow::CallNode { + MimetypeCall() { + this = API::getTopLevelMember("Rack").getMember("Mime").getAMethodCall("mime_type") + } + + private string getExtension() { + result = this.getArgument(0).getConstantValue().getStringlikeValue() + } + + string getMimeType() { mimeTypeMatches(this.getExtension(), result) } +} + +/** A `DataFlow::Node` returned from a rack request. */ +class ResponseNode extends PotentialResponseNode, Http::Server::HttpResponse::Range { + ResponseNode() { this = any(AppCandidate app).getResponse() } + + override DataFlow::Node getBody() { result = this.getElement(2) } + + override DataFlow::Node getMimetypeOrContentTypeArg() { + exists(DataFlow::Node headers | headers = this.getHeaders() | + // set via `headers.content_type=` + exists( + DataFlow::CallNode contentTypeAssignment, Assignment assignment, + DataFlow::PostUpdateNode postUpdateHeaders + | + contentTypeAssignment.getMethodName() = "content_type=" and + assignment = + contentTypeAssignment.getArgument(0).(DataFlow::OperationNode).asOperationAstNode() and + postUpdateHeaders.(DataFlow::LocalSourceNode).flowsTo(headers) and + postUpdateHeaders.getPreUpdateNode() = contentTypeAssignment.getReceiver() + | + result.asExpr().getExpr() = assignment.getRightOperand() + ) + or + // set within a hash + exists(DataFlow::HashLiteralNode headersHash | headersHash.flowsTo(headers) | + result = + headersHash + .getElementFromKey(any(ConstantValue v | + v.getStringlikeValue().toLowerCase() = "content-type" + )) + ) + ) + } + + // TODO + override string getMimetypeDefault() { none() } +} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/MimeTypes.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/MimeTypes.qll new file mode 100644 index 00000000000..ed5bad4b8a6 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/MimeTypes.qll @@ -0,0 +1,1285 @@ +predicate mimeTypeMatches(string ext, string mimeType) { + ext = ".123" and mimeType = "application/vnd.lotus-1-2-3" + or + ext = ".3dml" and mimeType = "text/vnd.in3d.3dml" + or + ext = ".3g2" and mimeType = "video/3gpp2" + or + ext = ".3gp" and mimeType = "video/3gpp" + or + ext = ".a" and mimeType = "application/octet-stream" + or + ext = ".acc" and mimeType = "application/vnd.americandynamics.acc" + or + ext = ".ace" and mimeType = "application/x-ace-compressed" + or + ext = ".acu" and mimeType = "application/vnd.acucobol" + or + ext = ".aep" and mimeType = "application/vnd.audiograph" + or + ext = ".afp" and mimeType = "application/vnd.ibm.modcap" + or + ext = ".ai" and mimeType = "application/postscript" + or + ext = ".aif" and mimeType = "audio/x-aiff" + or + ext = ".aiff" and mimeType = "audio/x-aiff" + or + ext = ".ami" and mimeType = "application/vnd.amiga.ami" + or + ext = ".apng" and mimeType = "image/apng" + or + ext = ".appcache" and mimeType = "text/cache-manifest" + or + ext = ".apr" and mimeType = "application/vnd.lotus-approach" + or + ext = ".asc" and mimeType = "application/pgp-signature" + or + ext = ".asf" and mimeType = "video/x-ms-asf" + or + ext = ".asm" and mimeType = "text/x-asm" + or + ext = ".aso" and mimeType = "application/vnd.accpac.simply.aso" + or + ext = ".asx" and mimeType = "video/x-ms-asf" + or + ext = ".atc" and mimeType = "application/vnd.acucorp" + or + ext = ".atom" and mimeType = "application/atom+xml" + or + ext = ".atomcat" and mimeType = "application/atomcat+xml" + or + ext = ".atomsvc" and mimeType = "application/atomsvc+xml" + or + ext = ".atx" and mimeType = "application/vnd.antix.game-component" + or + ext = ".au" and mimeType = "audio/basic" + or + ext = ".avi" and mimeType = "video/x-msvideo" + or + ext = ".avif" and mimeType = "image/avif" + or + ext = ".bat" and mimeType = "application/x-msdownload" + or + ext = ".bcpio" and mimeType = "application/x-bcpio" + or + ext = ".bdm" and mimeType = "application/vnd.syncml.dm+wbxml" + or + ext = ".bh2" and mimeType = "application/vnd.fujitsu.oasysprs" + or + ext = ".bin" and mimeType = "application/octet-stream" + or + ext = ".bmi" and mimeType = "application/vnd.bmi" + or + ext = ".bmp" and mimeType = "image/bmp" + or + ext = ".box" and mimeType = "application/vnd.previewsystems.box" + or + ext = ".btif" and mimeType = "image/prs.btif" + or + ext = ".bz" and mimeType = "application/x-bzip" + or + ext = ".bz2" and mimeType = "application/x-bzip2" + or + ext = ".c" and mimeType = "text/x-c" + or + ext = ".c4g" and mimeType = "application/vnd.clonk.c4group" + or + ext = ".cab" and mimeType = "application/vnd.ms-cab-compressed" + or + ext = ".cc" and mimeType = "text/x-c" + or + ext = ".ccxml" and mimeType = "application/ccxml+xml" + or + ext = ".cdbcmsg" and mimeType = "application/vnd.contact.cmsg" + or + ext = ".cdkey" and mimeType = "application/vnd.mediastation.cdkey" + or + ext = ".cdx" and mimeType = "chemical/x-cdx" + or + ext = ".cdxml" and mimeType = "application/vnd.chemdraw+xml" + or + ext = ".cdy" and mimeType = "application/vnd.cinderella" + or + ext = ".cer" and mimeType = "application/pkix-cert" + or + ext = ".cgm" and mimeType = "image/cgm" + or + ext = ".chat" and mimeType = "application/x-chat" + or + ext = ".chm" and mimeType = "application/vnd.ms-htmlhelp" + or + ext = ".chrt" and mimeType = "application/vnd.kde.kchart" + or + ext = ".cif" and mimeType = "chemical/x-cif" + or + ext = ".cii" and mimeType = "application/vnd.anser-web-certificate-issue-initiation" + or + ext = ".cil" and mimeType = "application/vnd.ms-artgalry" + or + ext = ".cla" and mimeType = "application/vnd.claymore" + or + ext = ".class" and mimeType = "application/octet-stream" + or + ext = ".clkk" and mimeType = "application/vnd.crick.clicker.keyboard" + or + ext = ".clkp" and mimeType = "application/vnd.crick.clicker.palette" + or + ext = ".clkt" and mimeType = "application/vnd.crick.clicker.template" + or + ext = ".clkw" and mimeType = "application/vnd.crick.clicker.wordbank" + or + ext = ".clkx" and mimeType = "application/vnd.crick.clicker" + or + ext = ".clp" and mimeType = "application/x-msclip" + or + ext = ".cmc" and mimeType = "application/vnd.cosmocaller" + or + ext = ".cmdf" and mimeType = "chemical/x-cmdf" + or + ext = ".cml" and mimeType = "chemical/x-cml" + or + ext = ".cmp" and mimeType = "application/vnd.yellowriver-custom-menu" + or + ext = ".cmx" and mimeType = "image/x-cmx" + or + ext = ".com" and mimeType = "application/x-msdownload" + or + ext = ".conf" and mimeType = "text/plain" + or + ext = ".cpio" and mimeType = "application/x-cpio" + or + ext = ".cpp" and mimeType = "text/x-c" + or + ext = ".cpt" and mimeType = "application/mac-compactpro" + or + ext = ".crd" and mimeType = "application/x-mscardfile" + or + ext = ".crl" and mimeType = "application/pkix-crl" + or + ext = ".crt" and mimeType = "application/x-x509-ca-cert" + or + ext = ".csh" and mimeType = "application/x-csh" + or + ext = ".csml" and mimeType = "chemical/x-csml" + or + ext = ".csp" and mimeType = "application/vnd.commonspace" + or + ext = ".css" and mimeType = "text/css" + or + ext = ".csv" and mimeType = "text/csv" + or + ext = ".curl" and mimeType = "application/vnd.curl" + or + ext = ".cww" and mimeType = "application/prs.cww" + or + ext = ".cxx" and mimeType = "text/x-c" + or + ext = ".daf" and mimeType = "application/vnd.mobius.daf" + or + ext = ".davmount" and mimeType = "application/davmount+xml" + or + ext = ".dcr" and mimeType = "application/x-director" + or + ext = ".dd2" and mimeType = "application/vnd.oma.dd2+xml" + or + ext = ".ddd" and mimeType = "application/vnd.fujixerox.ddd" + or + ext = ".deb" and mimeType = "application/x-debian-package" + or + ext = ".der" and mimeType = "application/x-x509-ca-cert" + or + ext = ".dfac" and mimeType = "application/vnd.dreamfactory" + or + ext = ".diff" and mimeType = "text/x-diff" + or + ext = ".dis" and mimeType = "application/vnd.mobius.dis" + or + ext = ".djv" and mimeType = "image/vnd.djvu" + or + ext = ".djvu" and mimeType = "image/vnd.djvu" + or + ext = ".dll" and mimeType = "application/x-msdownload" + or + ext = ".dmg" and mimeType = "application/octet-stream" + or + ext = ".dna" and mimeType = "application/vnd.dna" + or + ext = ".doc" and mimeType = "application/msword" + or + ext = ".docm" and mimeType = "application/vnd.ms-word.document.macroEnabled.12" + or + ext = ".docx" and + mimeType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + or + ext = ".dot" and mimeType = "application/msword" + or + ext = ".dotm" and mimeType = "application/vnd.ms-word.template.macroEnabled.12" + or + ext = ".dotx" and + mimeType = "application/vnd.openxmlformats-officedocument.wordprocessingml.template" + or + ext = ".dp" and mimeType = "application/vnd.osgi.dp" + or + ext = ".dpg" and mimeType = "application/vnd.dpgraph" + or + ext = ".dsc" and mimeType = "text/prs.lines.tag" + or + ext = ".dtd" and mimeType = "application/xml-dtd" + or + ext = ".dts" and mimeType = "audio/vnd.dts" + or + ext = ".dtshd" and mimeType = "audio/vnd.dts.hd" + or + ext = ".dv" and mimeType = "video/x-dv" + or + ext = ".dvi" and mimeType = "application/x-dvi" + or + ext = ".dwf" and mimeType = "model/vnd.dwf" + or + ext = ".dwg" and mimeType = "image/vnd.dwg" + or + ext = ".dxf" and mimeType = "image/vnd.dxf" + or + ext = ".dxp" and mimeType = "application/vnd.spotfire.dxp" + or + ext = ".ear" and mimeType = "application/java-archive" + or + ext = ".ecelp4800" and mimeType = "audio/vnd.nuera.ecelp4800" + or + ext = ".ecelp7470" and mimeType = "audio/vnd.nuera.ecelp7470" + or + ext = ".ecelp9600" and mimeType = "audio/vnd.nuera.ecelp9600" + or + ext = ".ecma" and mimeType = "application/ecmascript" + or + ext = ".edm" and mimeType = "application/vnd.novadigm.edm" + or + ext = ".edx" and mimeType = "application/vnd.novadigm.edx" + or + ext = ".efif" and mimeType = "application/vnd.picsel" + or + ext = ".ei6" and mimeType = "application/vnd.pg.osasli" + or + ext = ".eml" and mimeType = "message/rfc822" + or + ext = ".eol" and mimeType = "audio/vnd.digital-winds" + or + ext = ".eot" and mimeType = "application/vnd.ms-fontobject" + or + ext = ".eps" and mimeType = "application/postscript" + or + ext = ".es3" and mimeType = "application/vnd.eszigno3+xml" + or + ext = ".esf" and mimeType = "application/vnd.epson.esf" + or + ext = ".etx" and mimeType = "text/x-setext" + or + ext = ".exe" and mimeType = "application/x-msdownload" + or + ext = ".ext" and mimeType = "application/vnd.novadigm.ext" + or + ext = ".ez" and mimeType = "application/andrew-inset" + or + ext = ".ez2" and mimeType = "application/vnd.ezpix-album" + or + ext = ".ez3" and mimeType = "application/vnd.ezpix-package" + or + ext = ".f" and mimeType = "text/x-fortran" + or + ext = ".f77" and mimeType = "text/x-fortran" + or + ext = ".f90" and mimeType = "text/x-fortran" + or + ext = ".fbs" and mimeType = "image/vnd.fastbidsheet" + or + ext = ".fdf" and mimeType = "application/vnd.fdf" + or + ext = ".fe_launch" and mimeType = "application/vnd.denovo.fcselayout-link" + or + ext = ".fg5" and mimeType = "application/vnd.fujitsu.oasysgp" + or + ext = ".fli" and mimeType = "video/x-fli" + or + ext = ".flif" and mimeType = "image/flif" + or + ext = ".flo" and mimeType = "application/vnd.micrografx.flo" + or + ext = ".flv" and mimeType = "video/x-flv" + or + ext = ".flw" and mimeType = "application/vnd.kde.kivio" + or + ext = ".flx" and mimeType = "text/vnd.fmi.flexstor" + or + ext = ".fly" and mimeType = "text/vnd.fly" + or + ext = ".fm" and mimeType = "application/vnd.framemaker" + or + ext = ".fnc" and mimeType = "application/vnd.frogans.fnc" + or + ext = ".for" and mimeType = "text/x-fortran" + or + ext = ".fpx" and mimeType = "image/vnd.fpx" + or + ext = ".fsc" and mimeType = "application/vnd.fsc.weblaunch" + or + ext = ".fst" and mimeType = "image/vnd.fst" + or + ext = ".ftc" and mimeType = "application/vnd.fluxtime.clip" + or + ext = ".fti" and mimeType = "application/vnd.anser-web-funds-transfer-initiation" + or + ext = ".fvt" and mimeType = "video/vnd.fvt" + or + ext = ".fzs" and mimeType = "application/vnd.fuzzysheet" + or + ext = ".g3" and mimeType = "image/g3fax" + or + ext = ".gac" and mimeType = "application/vnd.groove-account" + or + ext = ".gdl" and mimeType = "model/vnd.gdl" + or + ext = ".gem" and mimeType = "application/octet-stream" + or + ext = ".gemspec" and mimeType = "text/x-script.ruby" + or + ext = ".ghf" and mimeType = "application/vnd.groove-help" + or + ext = ".gif" and mimeType = "image/gif" + or + ext = ".gim" and mimeType = "application/vnd.groove-identity-message" + or + ext = ".gmx" and mimeType = "application/vnd.gmx" + or + ext = ".gph" and mimeType = "application/vnd.flographit" + or + ext = ".gqf" and mimeType = "application/vnd.grafeq" + or + ext = ".gram" and mimeType = "application/srgs" + or + ext = ".grv" and mimeType = "application/vnd.groove-injector" + or + ext = ".grxml" and mimeType = "application/srgs+xml" + or + ext = ".gtar" and mimeType = "application/x-gtar" + or + ext = ".gtm" and mimeType = "application/vnd.groove-tool-message" + or + ext = ".gtw" and mimeType = "model/vnd.gtw" + or + ext = ".gv" and mimeType = "text/vnd.graphviz" + or + ext = ".gz" and mimeType = "application/x-gzip" + or + ext = ".h" and mimeType = "text/x-c" + or + ext = ".h261" and mimeType = "video/h261" + or + ext = ".h263" and mimeType = "video/h263" + or + ext = ".h264" and mimeType = "video/h264" + or + ext = ".hbci" and mimeType = "application/vnd.hbci" + or + ext = ".hdf" and mimeType = "application/x-hdf" + or + ext = ".heic" and mimeType = "image/heic" + or + ext = ".heics" and mimeType = "image/heic-sequence" + or + ext = ".heif" and mimeType = "image/heif" + or + ext = ".heifs" and mimeType = "image/heif-sequence" + or + ext = ".hh" and mimeType = "text/x-c" + or + ext = ".hlp" and mimeType = "application/winhlp" + or + ext = ".hpgl" and mimeType = "application/vnd.hp-hpgl" + or + ext = ".hpid" and mimeType = "application/vnd.hp-hpid" + or + ext = ".hps" and mimeType = "application/vnd.hp-hps" + or + ext = ".hqx" and mimeType = "application/mac-binhex40" + or + ext = ".htc" and mimeType = "text/x-component" + or + ext = ".htke" and mimeType = "application/vnd.kenameaapp" + or + ext = ".htm" and mimeType = "text/html" + or + ext = ".html" and mimeType = "text/html" + or + ext = ".hvd" and mimeType = "application/vnd.yamaha.hv-dic" + or + ext = ".hvp" and mimeType = "application/vnd.yamaha.hv-voice" + or + ext = ".hvs" and mimeType = "application/vnd.yamaha.hv-script" + or + ext = ".icc" and mimeType = "application/vnd.iccprofile" + or + ext = ".ice" and mimeType = "x-conference/x-cooltalk" + or + ext = ".ico" and mimeType = "image/vnd.microsoft.icon" + or + ext = ".ics" and mimeType = "text/calendar" + or + ext = ".ief" and mimeType = "image/ief" + or + ext = ".ifb" and mimeType = "text/calendar" + or + ext = ".ifm" and mimeType = "application/vnd.shana.informed.formdata" + or + ext = ".igl" and mimeType = "application/vnd.igloader" + or + ext = ".igs" and mimeType = "model/iges" + or + ext = ".igx" and mimeType = "application/vnd.micrografx.igx" + or + ext = ".iif" and mimeType = "application/vnd.shana.informed.interchange" + or + ext = ".imp" and mimeType = "application/vnd.accpac.simply.imp" + or + ext = ".ims" and mimeType = "application/vnd.ms-ims" + or + ext = ".ipk" and mimeType = "application/vnd.shana.informed.package" + or + ext = ".irm" and mimeType = "application/vnd.ibm.rights-management" + or + ext = ".irp" and mimeType = "application/vnd.irepository.package+xml" + or + ext = ".iso" and mimeType = "application/octet-stream" + or + ext = ".itp" and mimeType = "application/vnd.shana.informed.formtemplate" + or + ext = ".ivp" and mimeType = "application/vnd.immervision-ivp" + or + ext = ".ivu" and mimeType = "application/vnd.immervision-ivu" + or + ext = ".jad" and mimeType = "text/vnd.sun.j2me.app-descriptor" + or + ext = ".jam" and mimeType = "application/vnd.jam" + or + ext = ".jar" and mimeType = "application/java-archive" + or + ext = ".java" and mimeType = "text/x-java-source" + or + ext = ".jisp" and mimeType = "application/vnd.jisp" + or + ext = ".jlt" and mimeType = "application/vnd.hp-jlyt" + or + ext = ".jnlp" and mimeType = "application/x-java-jnlp-file" + or + ext = ".joda" and mimeType = "application/vnd.joost.joda-archive" + or + ext = ".jp2" and mimeType = "image/jp2" + or + ext = ".jpeg" and mimeType = "image/jpeg" + or + ext = ".jpg" and mimeType = "image/jpeg" + or + ext = ".jpgv" and mimeType = "video/jpeg" + or + ext = ".jpm" and mimeType = "video/jpm" + or + ext = ".js" and mimeType = "application/javascript" + or + ext = ".json" and mimeType = "application/json" + or + ext = ".karbon" and mimeType = "application/vnd.kde.karbon" + or + ext = ".kfo" and mimeType = "application/vnd.kde.kformula" + or + ext = ".kia" and mimeType = "application/vnd.kidspiration" + or + ext = ".kml" and mimeType = "application/vnd.google-earth.kml+xml" + or + ext = ".kmz" and mimeType = "application/vnd.google-earth.kmz" + or + ext = ".kne" and mimeType = "application/vnd.kinar" + or + ext = ".kon" and mimeType = "application/vnd.kde.kontour" + or + ext = ".kpr" and mimeType = "application/vnd.kde.kpresenter" + or + ext = ".ksp" and mimeType = "application/vnd.kde.kspread" + or + ext = ".ktz" and mimeType = "application/vnd.kahootz" + or + ext = ".kwd" and mimeType = "application/vnd.kde.kword" + or + ext = ".latex" and mimeType = "application/x-latex" + or + ext = ".lbd" and mimeType = "application/vnd.llamagraphics.life-balance.desktop" + or + ext = ".lbe" and mimeType = "application/vnd.llamagraphics.life-balance.exchange+xml" + or + ext = ".les" and mimeType = "application/vnd.hhe.lesson-player" + or + ext = ".link66" and mimeType = "application/vnd.route66.link66+xml" + or + ext = ".log" and mimeType = "text/plain" + or + ext = ".lostxml" and mimeType = "application/lost+xml" + or + ext = ".lrm" and mimeType = "application/vnd.ms-lrm" + or + ext = ".ltf" and mimeType = "application/vnd.frogans.ltf" + or + ext = ".lvp" and mimeType = "audio/vnd.lucent.voice" + or + ext = ".lwp" and mimeType = "application/vnd.lotus-wordpro" + or + ext = ".m3u" and mimeType = "audio/x-mpegurl" + or + ext = ".m3u8" and mimeType = "application/x-mpegurl" + or + ext = ".m4a" and mimeType = "audio/mp4a-latm" + or + ext = ".m4v" and mimeType = "video/mp4" + or + ext = ".ma" and mimeType = "application/mathematica" + or + ext = ".mag" and mimeType = "application/vnd.ecowin.chart" + or + ext = ".man" and mimeType = "text/troff" + or + ext = ".manifest" and mimeType = "text/cache-manifest" + or + ext = ".mathml" and mimeType = "application/mathml+xml" + or + ext = ".mbk" and mimeType = "application/vnd.mobius.mbk" + or + ext = ".mbox" and mimeType = "application/mbox" + or + ext = ".mc1" and mimeType = "application/vnd.medcalcdata" + or + ext = ".mcd" and mimeType = "application/vnd.mcd" + or + ext = ".mdb" and mimeType = "application/x-msaccess" + or + ext = ".mdi" and mimeType = "image/vnd.ms-modi" + or + ext = ".mdoc" and mimeType = "text/troff" + or + ext = ".me" and mimeType = "text/troff" + or + ext = ".mfm" and mimeType = "application/vnd.mfmp" + or + ext = ".mgz" and mimeType = "application/vnd.proteus.magazine" + or + ext = ".mid" and mimeType = "audio/midi" + or + ext = ".midi" and mimeType = "audio/midi" + or + ext = ".mif" and mimeType = "application/vnd.mif" + or + ext = ".mime" and mimeType = "message/rfc822" + or + ext = ".mj2" and mimeType = "video/mj2" + or + ext = ".mlp" and mimeType = "application/vnd.dolby.mlp" + or + ext = ".mmd" and mimeType = "application/vnd.chipnuts.karaoke-mmd" + or + ext = ".mmf" and mimeType = "application/vnd.smaf" + or + ext = ".mml" and mimeType = "application/mathml+xml" + or + ext = ".mmr" and mimeType = "image/vnd.fujixerox.edmics-mmr" + or + ext = ".mng" and mimeType = "video/x-mng" + or + ext = ".mny" and mimeType = "application/x-msmoney" + or + ext = ".mov" and mimeType = "video/quicktime" + or + ext = ".movie" and mimeType = "video/x-sgi-movie" + or + ext = ".mp3" and mimeType = "audio/mpeg" + or + ext = ".mp4" and mimeType = "video/mp4" + or + ext = ".mp4a" and mimeType = "audio/mp4" + or + ext = ".mp4s" and mimeType = "application/mp4" + or + ext = ".mp4v" and mimeType = "video/mp4" + or + ext = ".mpc" and mimeType = "application/vnd.mophun.certificate" + or + ext = ".mpd" and mimeType = "application/dash+xml" + or + ext = ".mpeg" and mimeType = "video/mpeg" + or + ext = ".mpg" and mimeType = "video/mpeg" + or + ext = ".mpga" and mimeType = "audio/mpeg" + or + ext = ".mpkg" and mimeType = "application/vnd.apple.installer+xml" + or + ext = ".mpm" and mimeType = "application/vnd.blueice.multipass" + or + ext = ".mpn" and mimeType = "application/vnd.mophun.application" + or + ext = ".mpp" and mimeType = "application/vnd.ms-project" + or + ext = ".mpy" and mimeType = "application/vnd.ibm.minipay" + or + ext = ".mqy" and mimeType = "application/vnd.mobius.mqy" + or + ext = ".mrc" and mimeType = "application/marc" + or + ext = ".ms" and mimeType = "text/troff" + or + ext = ".mscml" and mimeType = "application/mediaservercontrol+xml" + or + ext = ".mseq" and mimeType = "application/vnd.mseq" + or + ext = ".msf" and mimeType = "application/vnd.epson.msf" + or + ext = ".msh" and mimeType = "model/mesh" + or + ext = ".msi" and mimeType = "application/x-msdownload" + or + ext = ".msl" and mimeType = "application/vnd.mobius.msl" + or + ext = ".msty" and mimeType = "application/vnd.muvee.style" + or + ext = ".mts" and mimeType = "model/vnd.mts" + or + ext = ".mus" and mimeType = "application/vnd.musician" + or + ext = ".mvb" and mimeType = "application/x-msmediaview" + or + ext = ".mwf" and mimeType = "application/vnd.mfer" + or + ext = ".mxf" and mimeType = "application/mxf" + or + ext = ".mxl" and mimeType = "application/vnd.recordare.musicxml" + or + ext = ".mxml" and mimeType = "application/xv+xml" + or + ext = ".mxs" and mimeType = "application/vnd.triscape.mxs" + or + ext = ".mxu" and mimeType = "video/vnd.mpegurl" + or + ext = ".n" and mimeType = "application/vnd.nokia.n-gage.symbian.install" + or + ext = ".nc" and mimeType = "application/x-netcdf" + or + ext = ".ngdat" and mimeType = "application/vnd.nokia.n-gage.data" + or + ext = ".nlu" and mimeType = "application/vnd.neurolanguage.nlu" + or + ext = ".nml" and mimeType = "application/vnd.enliven" + or + ext = ".nnd" and mimeType = "application/vnd.noblenet-directory" + or + ext = ".nns" and mimeType = "application/vnd.noblenet-sealer" + or + ext = ".nnw" and mimeType = "application/vnd.noblenet-web" + or + ext = ".npx" and mimeType = "image/vnd.net-fpx" + or + ext = ".nsf" and mimeType = "application/vnd.lotus-notes" + or + ext = ".oa2" and mimeType = "application/vnd.fujitsu.oasys2" + or + ext = ".oa3" and mimeType = "application/vnd.fujitsu.oasys3" + or + ext = ".oas" and mimeType = "application/vnd.fujitsu.oasys" + or + ext = ".obd" and mimeType = "application/x-msbinder" + or + ext = ".oda" and mimeType = "application/oda" + or + ext = ".odc" and mimeType = "application/vnd.oasis.opendocument.chart" + or + ext = ".odf" and mimeType = "application/vnd.oasis.opendocument.formula" + or + ext = ".odg" and mimeType = "application/vnd.oasis.opendocument.graphics" + or + ext = ".odi" and mimeType = "application/vnd.oasis.opendocument.image" + or + ext = ".odp" and mimeType = "application/vnd.oasis.opendocument.presentation" + or + ext = ".ods" and mimeType = "application/vnd.oasis.opendocument.spreadsheet" + or + ext = ".odt" and mimeType = "application/vnd.oasis.opendocument.text" + or + ext = ".oga" and mimeType = "audio/ogg" + or + ext = ".ogg" and mimeType = "application/ogg" + or + ext = ".ogv" and mimeType = "video/ogg" + or + ext = ".ogx" and mimeType = "application/ogg" + or + ext = ".org" and mimeType = "application/vnd.lotus-organizer" + or + ext = ".otc" and mimeType = "application/vnd.oasis.opendocument.chart-template" + or + ext = ".otf" and mimeType = "application/vnd.oasis.opendocument.formula-template" + or + ext = ".otg" and mimeType = "application/vnd.oasis.opendocument.graphics-template" + or + ext = ".oth" and mimeType = "application/vnd.oasis.opendocument.text-web" + or + ext = ".oti" and mimeType = "application/vnd.oasis.opendocument.image-template" + or + ext = ".otm" and mimeType = "application/vnd.oasis.opendocument.text-master" + or + ext = ".ots" and mimeType = "application/vnd.oasis.opendocument.spreadsheet-template" + or + ext = ".ott" and mimeType = "application/vnd.oasis.opendocument.text-template" + or + ext = ".oxt" and mimeType = "application/vnd.openofficeorg.extension" + or + ext = ".p" and mimeType = "text/x-pascal" + or + ext = ".p10" and mimeType = "application/pkcs10" + or + ext = ".p12" and mimeType = "application/x-pkcs12" + or + ext = ".p7b" and mimeType = "application/x-pkcs7-certificates" + or + ext = ".p7m" and mimeType = "application/pkcs7-mime" + or + ext = ".p7r" and mimeType = "application/x-pkcs7-certreqresp" + or + ext = ".p7s" and mimeType = "application/pkcs7-signature" + or + ext = ".pas" and mimeType = "text/x-pascal" + or + ext = ".pbd" and mimeType = "application/vnd.powerbuilder6" + or + ext = ".pbm" and mimeType = "image/x-portable-bitmap" + or + ext = ".pcl" and mimeType = "application/vnd.hp-pcl" + or + ext = ".pclxl" and mimeType = "application/vnd.hp-pclxl" + or + ext = ".pcx" and mimeType = "image/x-pcx" + or + ext = ".pdb" and mimeType = "chemical/x-pdb" + or + ext = ".pdf" and mimeType = "application/pdf" + or + ext = ".pem" and mimeType = "application/x-x509-ca-cert" + or + ext = ".pfr" and mimeType = "application/font-tdpfr" + or + ext = ".pgm" and mimeType = "image/x-portable-graymap" + or + ext = ".pgn" and mimeType = "application/x-chess-pgn" + or + ext = ".pgp" and mimeType = "application/pgp-encrypted" + or + ext = ".pic" and mimeType = "image/x-pict" + or + ext = ".pict" and mimeType = "image/pict" + or + ext = ".pkg" and mimeType = "application/octet-stream" + or + ext = ".pki" and mimeType = "application/pkixcmp" + or + ext = ".pkipath" and mimeType = "application/pkix-pkipath" + or + ext = ".pl" and mimeType = "text/x-script.perl" + or + ext = ".plb" and mimeType = "application/vnd.3gpp.pic-bw-large" + or + ext = ".plc" and mimeType = "application/vnd.mobius.plc" + or + ext = ".plf" and mimeType = "application/vnd.pocketlearn" + or + ext = ".pls" and mimeType = "application/pls+xml" + or + ext = ".pm" and mimeType = "text/x-script.perl-module" + or + ext = ".pml" and mimeType = "application/vnd.ctc-posml" + or + ext = ".png" and mimeType = "image/png" + or + ext = ".pnm" and mimeType = "image/x-portable-anymap" + or + ext = ".pntg" and mimeType = "image/x-macpaint" + or + ext = ".portpkg" and mimeType = "application/vnd.macports.portpkg" + or + ext = ".pot" and mimeType = "application/vnd.ms-powerpoint" + or + ext = ".potm" and mimeType = "application/vnd.ms-powerpoint.template.macroEnabled.12" + or + ext = ".potx" and + mimeType = "application/vnd.openxmlformats-officedocument.presentationml.template" + or + ext = ".ppa" and mimeType = "application/vnd.ms-powerpoint" + or + ext = ".ppam" and mimeType = "application/vnd.ms-powerpoint.addin.macroEnabled.12" + or + ext = ".ppd" and mimeType = "application/vnd.cups-ppd" + or + ext = ".ppm" and mimeType = "image/x-portable-pixmap" + or + ext = ".pps" and mimeType = "application/vnd.ms-powerpoint" + or + ext = ".ppsm" and mimeType = "application/vnd.ms-powerpoint.slideshow.macroEnabled.12" + or + ext = ".ppsx" and + mimeType = "application/vnd.openxmlformats-officedocument.presentationml.slideshow" + or + ext = ".ppt" and mimeType = "application/vnd.ms-powerpoint" + or + ext = ".pptm" and mimeType = "application/vnd.ms-powerpoint.presentation.macroEnabled.12" + or + ext = ".pptx" and + mimeType = "application/vnd.openxmlformats-officedocument.presentationml.presentation" + or + ext = ".prc" and mimeType = "application/vnd.palm" + or + ext = ".pre" and mimeType = "application/vnd.lotus-freelance" + or + ext = ".prf" and mimeType = "application/pics-rules" + or + ext = ".ps" and mimeType = "application/postscript" + or + ext = ".psb" and mimeType = "application/vnd.3gpp.pic-bw-small" + or + ext = ".psd" and mimeType = "image/vnd.adobe.photoshop" + or + ext = ".ptid" and mimeType = "application/vnd.pvi.ptid1" + or + ext = ".pub" and mimeType = "application/x-mspublisher" + or + ext = ".pvb" and mimeType = "application/vnd.3gpp.pic-bw-var" + or + ext = ".pwn" and mimeType = "application/vnd.3m.post-it-notes" + or + ext = ".py" and mimeType = "text/x-script.python" + or + ext = ".pya" and mimeType = "audio/vnd.ms-playready.media.pya" + or + ext = ".pyv" and mimeType = "video/vnd.ms-playready.media.pyv" + or + ext = ".qam" and mimeType = "application/vnd.epson.quickanime" + or + ext = ".qbo" and mimeType = "application/vnd.intu.qbo" + or + ext = ".qfx" and mimeType = "application/vnd.intu.qfx" + or + ext = ".qps" and mimeType = "application/vnd.publishare-delta-tree" + or + ext = ".qt" and mimeType = "video/quicktime" + or + ext = ".qtif" and mimeType = "image/x-quicktime" + or + ext = ".qxd" and mimeType = "application/vnd.quark.quarkxpress" + or + ext = ".ra" and mimeType = "audio/x-pn-realaudio" + or + ext = ".rake" and mimeType = "text/x-script.ruby" + or + ext = ".ram" and mimeType = "audio/x-pn-realaudio" + or + ext = ".rar" and mimeType = "application/x-rar-compressed" + or + ext = ".ras" and mimeType = "image/x-cmu-raster" + or + ext = ".rb" and mimeType = "text/x-script.ruby" + or + ext = ".rcprofile" and mimeType = "application/vnd.ipunplugged.rcprofile" + or + ext = ".rdf" and mimeType = "application/rdf+xml" + or + ext = ".rdz" and mimeType = "application/vnd.data-vision.rdz" + or + ext = ".rep" and mimeType = "application/vnd.businessobjects" + or + ext = ".rgb" and mimeType = "image/x-rgb" + or + ext = ".rif" and mimeType = "application/reginfo+xml" + or + ext = ".rl" and mimeType = "application/resource-lists+xml" + or + ext = ".rlc" and mimeType = "image/vnd.fujixerox.edmics-rlc" + or + ext = ".rld" and mimeType = "application/resource-lists-diff+xml" + or + ext = ".rm" and mimeType = "application/vnd.rn-realmedia" + or + ext = ".rmp" and mimeType = "audio/x-pn-realaudio-plugin" + or + ext = ".rms" and mimeType = "application/vnd.jcp.javame.midlet-rms" + or + ext = ".rnc" and mimeType = "application/relax-ng-compact-syntax" + or + ext = ".roff" and mimeType = "text/troff" + or + ext = ".rpm" and mimeType = "application/x-redhat-package-manager" + or + ext = ".rpss" and mimeType = "application/vnd.nokia.radio-presets" + or + ext = ".rpst" and mimeType = "application/vnd.nokia.radio-preset" + or + ext = ".rq" and mimeType = "application/sparql-query" + or + ext = ".rs" and mimeType = "application/rls-services+xml" + or + ext = ".rsd" and mimeType = "application/rsd+xml" + or + ext = ".rss" and mimeType = "application/rss+xml" + or + ext = ".rtf" and mimeType = "application/rtf" + or + ext = ".rtx" and mimeType = "text/richtext" + or + ext = ".ru" and mimeType = "text/x-script.ruby" + or + ext = ".s" and mimeType = "text/x-asm" + or + ext = ".saf" and mimeType = "application/vnd.yamaha.smaf-audio" + or + ext = ".sbml" and mimeType = "application/sbml+xml" + or + ext = ".sc" and mimeType = "application/vnd.ibm.secure-container" + or + ext = ".scd" and mimeType = "application/x-msschedule" + or + ext = ".scm" and mimeType = "application/vnd.lotus-screencam" + or + ext = ".scq" and mimeType = "application/scvp-cv-request" + or + ext = ".scs" and mimeType = "application/scvp-cv-response" + or + ext = ".sdkm" and mimeType = "application/vnd.solent.sdkm+xml" + or + ext = ".sdp" and mimeType = "application/sdp" + or + ext = ".see" and mimeType = "application/vnd.seemail" + or + ext = ".sema" and mimeType = "application/vnd.sema" + or + ext = ".semd" and mimeType = "application/vnd.semd" + or + ext = ".semf" and mimeType = "application/vnd.semf" + or + ext = ".setpay" and mimeType = "application/set-payment-initiation" + or + ext = ".setreg" and mimeType = "application/set-registration-initiation" + or + ext = ".sfd" and mimeType = "application/vnd.hydrostatix.sof-data" + or + ext = ".sfs" and mimeType = "application/vnd.spotfire.sfs" + or + ext = ".sgm" and mimeType = "text/sgml" + or + ext = ".sgml" and mimeType = "text/sgml" + or + ext = ".sh" and mimeType = "application/x-sh" + or + ext = ".shar" and mimeType = "application/x-shar" + or + ext = ".shf" and mimeType = "application/shf+xml" + or + ext = ".sig" and mimeType = "application/pgp-signature" + or + ext = ".sit" and mimeType = "application/x-stuffit" + or + ext = ".sitx" and mimeType = "application/x-stuffitx" + or + ext = ".skp" and mimeType = "application/vnd.koan" + or + ext = ".slt" and mimeType = "application/vnd.epson.salt" + or + ext = ".smi" and mimeType = "application/smil+xml" + or + ext = ".snd" and mimeType = "audio/basic" + or + ext = ".so" and mimeType = "application/octet-stream" + or + ext = ".spf" and mimeType = "application/vnd.yamaha.smaf-phrase" + or + ext = ".spl" and mimeType = "application/x-futuresplash" + or + ext = ".spot" and mimeType = "text/vnd.in3d.spot" + or + ext = ".spp" and mimeType = "application/scvp-vp-response" + or + ext = ".spq" and mimeType = "application/scvp-vp-request" + or + ext = ".src" and mimeType = "application/x-wais-source" + or + ext = ".srt" and mimeType = "text/srt" + or + ext = ".srx" and mimeType = "application/sparql-results+xml" + or + ext = ".sse" and mimeType = "application/vnd.kodak-descriptor" + or + ext = ".ssf" and mimeType = "application/vnd.epson.ssf" + or + ext = ".ssml" and mimeType = "application/ssml+xml" + or + ext = ".stf" and mimeType = "application/vnd.wt.stf" + or + ext = ".stk" and mimeType = "application/hyperstudio" + or + ext = ".str" and mimeType = "application/vnd.pg.format" + or + ext = ".sus" and mimeType = "application/vnd.sus-calendar" + or + ext = ".sv4cpio" and mimeType = "application/x-sv4cpio" + or + ext = ".sv4crc" and mimeType = "application/x-sv4crc" + or + ext = ".svd" and mimeType = "application/vnd.svd" + or + ext = ".svg" and mimeType = "image/svg+xml" + or + ext = ".svgz" and mimeType = "image/svg+xml" + or + ext = ".swf" and mimeType = "application/x-shockwave-flash" + or + ext = ".swi" and mimeType = "application/vnd.arastra.swi" + or + ext = ".t" and mimeType = "text/troff" + or + ext = ".tao" and mimeType = "application/vnd.tao.intent-module-archive" + or + ext = ".tar" and mimeType = "application/x-tar" + or + ext = ".tbz" and mimeType = "application/x-bzip-compressed-tar" + or + ext = ".tcap" and mimeType = "application/vnd.3gpp2.tcap" + or + ext = ".tcl" and mimeType = "application/x-tcl" + or + ext = ".tex" and mimeType = "application/x-tex" + or + ext = ".texi" and mimeType = "application/x-texinfo" + or + ext = ".texinfo" and mimeType = "application/x-texinfo" + or + ext = ".text" and mimeType = "text/plain" + or + ext = ".tif" and mimeType = "image/tiff" + or + ext = ".tiff" and mimeType = "image/tiff" + or + ext = ".tmo" and mimeType = "application/vnd.tmobile-livetv" + or + ext = ".torrent" and mimeType = "application/x-bittorrent" + or + ext = ".tpl" and mimeType = "application/vnd.groove-tool-template" + or + ext = ".tpt" and mimeType = "application/vnd.trid.tpt" + or + ext = ".tr" and mimeType = "text/troff" + or + ext = ".tra" and mimeType = "application/vnd.trueapp" + or + ext = ".trm" and mimeType = "application/x-msterminal" + or + ext = ".ts" and mimeType = "video/mp2t" + or + ext = ".tsv" and mimeType = "text/tab-separated-values" + or + ext = ".ttf" and mimeType = "application/octet-stream" + or + ext = ".twd" and mimeType = "application/vnd.simtech-mindmapper" + or + ext = ".txd" and mimeType = "application/vnd.genomatix.tuxedo" + or + ext = ".txf" and mimeType = "application/vnd.mobius.txf" + or + ext = ".txt" and mimeType = "text/plain" + or + ext = ".ufd" and mimeType = "application/vnd.ufdl" + or + ext = ".umj" and mimeType = "application/vnd.umajin" + or + ext = ".unityweb" and mimeType = "application/vnd.unity" + or + ext = ".uoml" and mimeType = "application/vnd.uoml+xml" + or + ext = ".uri" and mimeType = "text/uri-list" + or + ext = ".ustar" and mimeType = "application/x-ustar" + or + ext = ".utz" and mimeType = "application/vnd.uiq.theme" + or + ext = ".uu" and mimeType = "text/x-uuencode" + or + ext = ".vcd" and mimeType = "application/x-cdlink" + or + ext = ".vcf" and mimeType = "text/x-vcard" + or + ext = ".vcg" and mimeType = "application/vnd.groove-vcard" + or + ext = ".vcs" and mimeType = "text/x-vcalendar" + or + ext = ".vcx" and mimeType = "application/vnd.vcx" + or + ext = ".vis" and mimeType = "application/vnd.visionary" + or + ext = ".viv" and mimeType = "video/vnd.vivo" + or + ext = ".vrml" and mimeType = "model/vrml" + or + ext = ".vsd" and mimeType = "application/vnd.visio" + or + ext = ".vsf" and mimeType = "application/vnd.vsf" + or + ext = ".vtt" and mimeType = "text/vtt" + or + ext = ".vtu" and mimeType = "model/vnd.vtu" + or + ext = ".vxml" and mimeType = "application/voicexml+xml" + or + ext = ".war" and mimeType = "application/java-archive" + or + ext = ".wasm" and mimeType = "application/wasm" + or + ext = ".wav" and mimeType = "audio/x-wav" + or + ext = ".wax" and mimeType = "audio/x-ms-wax" + or + ext = ".wbmp" and mimeType = "image/vnd.wap.wbmp" + or + ext = ".wbs" and mimeType = "application/vnd.criticaltools.wbs+xml" + or + ext = ".wbxml" and mimeType = "application/vnd.wap.wbxml" + or + ext = ".webm" and mimeType = "video/webm" + or + ext = ".webp" and mimeType = "image/webp" + or + ext = ".wm" and mimeType = "video/x-ms-wm" + or + ext = ".wma" and mimeType = "audio/x-ms-wma" + or + ext = ".wmd" and mimeType = "application/x-ms-wmd" + or + ext = ".wmf" and mimeType = "application/x-msmetafile" + or + ext = ".wml" and mimeType = "text/vnd.wap.wml" + or + ext = ".wmlc" and mimeType = "application/vnd.wap.wmlc" + or + ext = ".wmls" and mimeType = "text/vnd.wap.wmlscript" + or + ext = ".wmlsc" and mimeType = "application/vnd.wap.wmlscriptc" + or + ext = ".wmv" and mimeType = "video/x-ms-wmv" + or + ext = ".wmx" and mimeType = "video/x-ms-wmx" + or + ext = ".wmz" and mimeType = "application/x-ms-wmz" + or + ext = ".woff" and mimeType = "application/font-woff" + or + ext = ".woff2" and mimeType = "application/font-woff2" + or + ext = ".wpd" and mimeType = "application/vnd.wordperfect" + or + ext = ".wpl" and mimeType = "application/vnd.ms-wpl" + or + ext = ".wps" and mimeType = "application/vnd.ms-works" + or + ext = ".wqd" and mimeType = "application/vnd.wqd" + or + ext = ".wri" and mimeType = "application/x-mswrite" + or + ext = ".wrl" and mimeType = "model/vrml" + or + ext = ".wsdl" and mimeType = "application/wsdl+xml" + or + ext = ".wspolicy" and mimeType = "application/wspolicy+xml" + or + ext = ".wtb" and mimeType = "application/vnd.webturbo" + or + ext = ".wvx" and mimeType = "video/x-ms-wvx" + or + ext = ".x3d" and mimeType = "application/vnd.hzn-3d-crossword" + or + ext = ".xar" and mimeType = "application/vnd.xara" + or + ext = ".xbd" and mimeType = "application/vnd.fujixerox.docuworks.binder" + or + ext = ".xbm" and mimeType = "image/x-xbitmap" + or + ext = ".xdm" and mimeType = "application/vnd.syncml.dm+xml" + or + ext = ".xdp" and mimeType = "application/vnd.adobe.xdp+xml" + or + ext = ".xdw" and mimeType = "application/vnd.fujixerox.docuworks" + or + ext = ".xenc" and mimeType = "application/xenc+xml" + or + ext = ".xer" and mimeType = "application/patch-ops-error+xml" + or + ext = ".xfdf" and mimeType = "application/vnd.adobe.xfdf" + or + ext = ".xfdl" and mimeType = "application/vnd.xfdl" + or + ext = ".xhtml" and mimeType = "application/xhtml+xml" + or + ext = ".xif" and mimeType = "image/vnd.xiff" + or + ext = ".xla" and mimeType = "application/vnd.ms-excel" + or + ext = ".xlam" and mimeType = "application/vnd.ms-excel.addin.macroEnabled.12" + or + ext = ".xls" and mimeType = "application/vnd.ms-excel" + or + ext = ".xlsb" and mimeType = "application/vnd.ms-excel.sheet.binary.macroEnabled.12" + or + ext = ".xlsx" and mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + or + ext = ".xlsm" and mimeType = "application/vnd.ms-excel.sheet.macroEnabled.12" + or + ext = ".xlt" and mimeType = "application/vnd.ms-excel" + or + ext = ".xltx" and + mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.template" + or + ext = ".xml" and mimeType = "application/xml" + or + ext = ".xo" and mimeType = "application/vnd.olpc-sugar" + or + ext = ".xop" and mimeType = "application/xop+xml" + or + ext = ".xpm" and mimeType = "image/x-xpixmap" + or + ext = ".xpr" and mimeType = "application/vnd.is-xpr" + or + ext = ".xps" and mimeType = "application/vnd.ms-xpsdocument" + or + ext = ".xpw" and mimeType = "application/vnd.intercon.formnet" + or + ext = ".xsl" and mimeType = "application/xml" + or + ext = ".xslt" and mimeType = "application/xslt+xml" + or + ext = ".xsm" and mimeType = "application/vnd.syncml+xml" + or + ext = ".xspf" and mimeType = "application/xspf+xml" + or + ext = ".xul" and mimeType = "application/vnd.mozilla.xul+xml" + or + ext = ".xwd" and mimeType = "image/x-xwindowdump" + or + ext = ".xyz" and mimeType = "chemical/x-xyz" + or + ext = ".yaml" and mimeType = "text/yaml" + or + ext = ".yml" and mimeType = "text/yaml" + or + ext = ".zaz" and mimeType = "application/vnd.zzazz.deck+xml" + or + ext = ".zip" and mimeType = "application/zip" + or + ext = ".zmm" and mimeType = "application/vnd.handheld-entertainment+xml" +} diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql index 6e18162a5e1..489531bdba4 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql @@ -1,3 +1,4 @@ +private import codeql.ruby.AST private import codeql.ruby.frameworks.Rack private import codeql.ruby.DataFlow @@ -8,3 +9,9 @@ query predicate rackResponseStatusCodes(Rack::ResponseNode resp, string status) then status = resp.getAStatusCode().toString() else status = "" } + +query predicate rackResponseContentTypes(Rack::ResponseNode resp, DataFlow::Node contentType) { + contentType = resp.getMimetypeOrContentTypeArg() +} + +query predicate mimetypeCalls(Rack::MimetypeCall c, string mimetype) { mimetype = c.getMimeType() } diff --git a/ruby/ql/test/library-tests/frameworks/rack/rack.rb b/ruby/ql/test/library-tests/frameworks/rack/rack.rb index c3b7729812b..2478faee3fc 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/rack.rb +++ b/ruby/ql/test/library-tests/frameworks/rack/rack.rb @@ -4,7 +4,8 @@ class HelloWorld if something_goes_wrong(env) status = 500 end - [status, {'Content-Type' => 'text/plain'}, ['Hello World']] + headers = {'Content-Type' => 'text/plain'} + [status, headers, ['Hello World']] end end @@ -15,6 +16,7 @@ class Proxy def call(the_env) status, headers, body = @app.call(the_env) + headers.content_type = Rack::Mime.mime_type(".gz") [status, headers, body] end end From b2958f87b2e7bdde32f182030888befffb872bdf Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Mon, 22 May 2023 13:56:53 +0100 Subject: [PATCH 019/364] ruby: rack - add redirect responses --- .../lib/codeql/ruby/frameworks/rack/Rack.qll | 59 +++++++++++-------- .../library-tests/frameworks/rack/Rack.ql | 4 ++ .../library-tests/frameworks/rack/rack.rb | 8 +++ 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll index b570f276c51..a36c4ba043f 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll @@ -82,6 +82,34 @@ class MimetypeCall extends DataFlow::CallNode { string getMimeType() { mimeTypeMatches(this.getExtension(), result) } } +bindingset[headerName] +private DataFlow::Node getHeaderValue(ResponseNode resp, string headerName) { + exists(DataFlow::Node headers | headers = resp.getHeaders() | + // set via `headers.=` + exists( + DataFlow::CallNode contentTypeAssignment, Assignment assignment, + DataFlow::PostUpdateNode postUpdateHeaders + | + contentTypeAssignment.getMethodName() = headerName.replaceAll("-", "_").toLowerCase() + "=" and + assignment = + contentTypeAssignment.getArgument(0).(DataFlow::OperationNode).asOperationAstNode() and + postUpdateHeaders.(DataFlow::LocalSourceNode).flowsTo(headers) and + postUpdateHeaders.getPreUpdateNode() = contentTypeAssignment.getReceiver() + | + result.asExpr().getExpr() = assignment.getRightOperand() + ) + or + // set within a hash + exists(DataFlow::HashLiteralNode headersHash | headersHash.flowsTo(headers) | + result = + headersHash + .getElementFromKey(any(ConstantValue v | + v.getStringlikeValue().toLowerCase() = headerName.toLowerCase() + )) + ) + ) +} + /** A `DataFlow::Node` returned from a rack request. */ class ResponseNode extends PotentialResponseNode, Http::Server::HttpResponse::Range { ResponseNode() { this = any(AppCandidate app).getResponse() } @@ -89,32 +117,15 @@ class ResponseNode extends PotentialResponseNode, Http::Server::HttpResponse::Ra override DataFlow::Node getBody() { result = this.getElement(2) } override DataFlow::Node getMimetypeOrContentTypeArg() { - exists(DataFlow::Node headers | headers = this.getHeaders() | - // set via `headers.content_type=` - exists( - DataFlow::CallNode contentTypeAssignment, Assignment assignment, - DataFlow::PostUpdateNode postUpdateHeaders - | - contentTypeAssignment.getMethodName() = "content_type=" and - assignment = - contentTypeAssignment.getArgument(0).(DataFlow::OperationNode).asOperationAstNode() and - postUpdateHeaders.(DataFlow::LocalSourceNode).flowsTo(headers) and - postUpdateHeaders.getPreUpdateNode() = contentTypeAssignment.getReceiver() - | - result.asExpr().getExpr() = assignment.getRightOperand() - ) - or - // set within a hash - exists(DataFlow::HashLiteralNode headersHash | headersHash.flowsTo(headers) | - result = - headersHash - .getElementFromKey(any(ConstantValue v | - v.getStringlikeValue().toLowerCase() = "content-type" - )) - ) - ) + result = getHeaderValue(this, "content-type") } // TODO override string getMimetypeDefault() { none() } } + +class RedirectResponse extends ResponseNode, Http::Server::HttpRedirectResponse::Range { + RedirectResponse() { this.getAStatusCode() = [300, 301, 302, 303, 307, 308] } + + override DataFlow::Node getRedirectLocation() { result = getHeaderValue(this, "location") } +} diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql index 489531bdba4..b4299d9d6f9 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql @@ -15,3 +15,7 @@ query predicate rackResponseContentTypes(Rack::ResponseNode resp, DataFlow::Node } query predicate mimetypeCalls(Rack::MimetypeCall c, string mimetype) { mimetype = c.getMimeType() } + +query predicate redirectResponses(Rack::RedirectResponse resp, DataFlow::Node location) { + location = resp.getRedirectLocation() +} diff --git a/ruby/ql/test/library-tests/frameworks/rack/rack.rb b/ruby/ql/test/library-tests/frameworks/rack/rack.rb index 2478faee3fc..c2e2598e5ec 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/rack.rb +++ b/ruby/ql/test/library-tests/frameworks/rack/rack.rb @@ -36,6 +36,14 @@ class Logger end end +class Redirector + def call(env) + status = 302 + headers = {'location' => '/foo.html'} + [status, headers, ['this is a redirect']] + end +end + class Foo def not_call(env) [1, 2, 3] From a5a15f380400c4999057ec13cbf2a1d69443d960 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 24 May 2023 15:49:59 +0100 Subject: [PATCH 020/364] Ruby: restructure rack model --- .../ruby/frameworks/ActionController.qll | 2 +- ruby/ql/lib/codeql/ruby/frameworks/Rack.qll | 7 +- .../lib/codeql/ruby/frameworks/rack/Rack.qll | 131 ------------------ .../ruby/frameworks/rack/internal/App.qll | 41 ++++++ .../rack/internal/{MimeTypes.qll => Mime.qll} | 17 +++ .../frameworks/rack/internal/Response.qll | 84 +++++++++++ .../library-tests/frameworks/rack/Rack.ql | 16 ++- 7 files changed, 160 insertions(+), 138 deletions(-) delete mode 100644 ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll rename ruby/ql/lib/codeql/ruby/frameworks/rack/internal/{MimeTypes.qll => Mime.qll} (98%) create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll index 480a1f78035..5899f38411d 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll @@ -326,7 +326,7 @@ private module Request { private import codeql.ruby.frameworks.Rack private class RackEnv extends Env { - RackEnv() { this = any(Rack::AppCandidate app).getEnv().getALocalUse() } + RackEnv() { this = any(Rack::App::AppCandidate app).getEnv().getALocalUse() } } /** diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll index ba969ae4c45..64ca7cc0b60 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll @@ -2,5 +2,10 @@ * Provides modeling for the Rack library. */ module Rack { - import rack.Rack + import rack.internal.App + import rack.internal.Mime + import rack.internal.Response::Public as Response + + /** DEPRECATED: Alias for App::AppCandidate */ + deprecated class AppCandidate = App::AppCandidate; } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll deleted file mode 100644 index a36c4ba043f..00000000000 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/Rack.qll +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Provides modeling for the Rack library. - */ - -private import codeql.ruby.AST -private import codeql.ruby.ApiGraphs -private import codeql.ruby.Concepts -private import codeql.ruby.controlflow.CfgNodes::ExprNodes -private import codeql.ruby.DataFlow -private import codeql.ruby.typetracking.TypeTracker -private import internal.MimeTypes - -/** - * A class that may be a rack application. - * This is a class that has a `call` method that takes a single argument - * (traditionally called `env`) and returns a rack-compatible response. - */ -class AppCandidate extends DataFlow::ClassNode { - private DataFlow::MethodNode call; - private PotentialResponseNode resp; - - AppCandidate() { - call = this.getInstanceMethod("call") and - call.getNumberOfParameters() = 1 and - call.getReturn() = trackRackResponse(resp) - } - - /** - * Gets the environment of the request, which is the lone parameter to the `call` method. - */ - DataFlow::ParameterNode getEnv() { result = call.getParameter(0) } - - /** Gets the response returned from the request. */ - PotentialResponseNode getResponse() { result = resp } -} - -private DataFlow::LocalSourceNode trackInt(TypeTracker t, int i) { - t.start() and - result.getConstantValue().isInt(i) - or - exists(TypeTracker t2 | result = trackInt(t2, i).track(t2, t)) -} - -private DataFlow::Node trackInt(int i) { trackInt(TypeTracker::end(), i).flowsTo(result) } - -private class PotentialResponseNode extends DataFlow::ArrayLiteralNode { - // [status, headers, body] - PotentialResponseNode() { this.getNumberOfArguments() = 3 } - - /** - * Gets an HTTP status code that may be returned in this response. - */ - int getAStatusCode() { this.getElement(0) = trackInt(result) } - - /** Gets the headers returned with this response. */ - DataFlow::Node getHeaders() { result = this.getElement(1) } - - /** Gets the body of this response. */ - DataFlow::Node getBody() { result = this.getElement(2) } -} - -private DataFlow::LocalSourceNode trackRackResponse(TypeTracker t, PotentialResponseNode n) { - t.start() and - result = n - or - exists(TypeTracker t2 | result = trackRackResponse(t2, n).track(t2, t)) -} - -private DataFlow::Node trackRackResponse(PotentialResponseNode n) { - trackRackResponse(TypeTracker::end(), n).flowsTo(result) -} - -class MimetypeCall extends DataFlow::CallNode { - MimetypeCall() { - this = API::getTopLevelMember("Rack").getMember("Mime").getAMethodCall("mime_type") - } - - private string getExtension() { - result = this.getArgument(0).getConstantValue().getStringlikeValue() - } - - string getMimeType() { mimeTypeMatches(this.getExtension(), result) } -} - -bindingset[headerName] -private DataFlow::Node getHeaderValue(ResponseNode resp, string headerName) { - exists(DataFlow::Node headers | headers = resp.getHeaders() | - // set via `headers.=` - exists( - DataFlow::CallNode contentTypeAssignment, Assignment assignment, - DataFlow::PostUpdateNode postUpdateHeaders - | - contentTypeAssignment.getMethodName() = headerName.replaceAll("-", "_").toLowerCase() + "=" and - assignment = - contentTypeAssignment.getArgument(0).(DataFlow::OperationNode).asOperationAstNode() and - postUpdateHeaders.(DataFlow::LocalSourceNode).flowsTo(headers) and - postUpdateHeaders.getPreUpdateNode() = contentTypeAssignment.getReceiver() - | - result.asExpr().getExpr() = assignment.getRightOperand() - ) - or - // set within a hash - exists(DataFlow::HashLiteralNode headersHash | headersHash.flowsTo(headers) | - result = - headersHash - .getElementFromKey(any(ConstantValue v | - v.getStringlikeValue().toLowerCase() = headerName.toLowerCase() - )) - ) - ) -} - -/** A `DataFlow::Node` returned from a rack request. */ -class ResponseNode extends PotentialResponseNode, Http::Server::HttpResponse::Range { - ResponseNode() { this = any(AppCandidate app).getResponse() } - - override DataFlow::Node getBody() { result = this.getElement(2) } - - override DataFlow::Node getMimetypeOrContentTypeArg() { - result = getHeaderValue(this, "content-type") - } - - // TODO - override string getMimetypeDefault() { none() } -} - -class RedirectResponse extends ResponseNode, Http::Server::HttpRedirectResponse::Range { - RedirectResponse() { this.getAStatusCode() = [300, 301, 302, 303, 307, 308] } - - override DataFlow::Node getRedirectLocation() { result = getHeaderValue(this, "location") } -} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll new file mode 100644 index 00000000000..7dbd7c7a840 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll @@ -0,0 +1,41 @@ +private import codeql.ruby.ApiGraphs +private import codeql.ruby.DataFlow +private import codeql.ruby.typetracking.TypeTracker +private import Response::Private as RP + +private DataFlow::LocalSourceNode trackRackResponse(TypeTracker t, RP::PotentialResponseNode n) { + t.start() and + result = n + or + exists(TypeTracker t2 | result = trackRackResponse(t2, n).track(t2, t)) +} + +private DataFlow::Node trackRackResponse(RP::PotentialResponseNode n) { + trackRackResponse(TypeTracker::end(), n).flowsTo(result) +} + +module App { + /** + * A class that may be a rack application. + * This is a class that has a `call` method that takes a single argument + * (traditionally called `env`) and returns a rack-compatible response. + */ + class AppCandidate extends DataFlow::ClassNode { + private DataFlow::MethodNode call; + private RP::PotentialResponseNode resp; + + AppCandidate() { + call = this.getInstanceMethod("call") and + call.getNumberOfParameters() = 1 and + call.getReturn() = trackRackResponse(resp) + } + + /** + * Gets the environment of the request, which is the lone parameter to the `call` method. + */ + DataFlow::ParameterNode getEnv() { result = call.getParameter(0) } + + /** Gets the response returned from the request. */ + RP::PotentialResponseNode getResponse() { result = resp } + } +} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/MimeTypes.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll similarity index 98% rename from ruby/ql/lib/codeql/ruby/frameworks/rack/internal/MimeTypes.qll rename to ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll index ed5bad4b8a6..502fe72fa51 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/MimeTypes.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll @@ -1,3 +1,6 @@ +private import codeql.ruby.ApiGraphs +private import codeql.ruby.DataFlow + predicate mimeTypeMatches(string ext, string mimeType) { ext = ".123" and mimeType = "application/vnd.lotus-1-2-3" or @@ -1283,3 +1286,17 @@ predicate mimeTypeMatches(string ext, string mimeType) { or ext = ".zmm" and mimeType = "application/vnd.handheld-entertainment+xml" } + +module Mime { + class MimetypeCall extends DataFlow::CallNode { + MimetypeCall() { + this = API::getTopLevelMember("Rack").getMember("Mime").getAMethodCall("mime_type") + } + + private string getExtension() { + result = this.getArgument(0).getConstantValue().getStringlikeValue() + } + + string getMimeType() { mimeTypeMatches(this.getExtension(), result) } + } +} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll new file mode 100644 index 00000000000..f7fb1d31177 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll @@ -0,0 +1,84 @@ +private import codeql.ruby.AST +private import codeql.ruby.ApiGraphs +private import codeql.ruby.Concepts +private import codeql.ruby.controlflow.CfgNodes::ExprNodes +private import codeql.ruby.DataFlow +private import codeql.ruby.typetracking.TypeTracker +private import App as A + +module Private { + private DataFlow::LocalSourceNode trackInt(TypeTracker t, int i) { + t.start() and + result.getConstantValue().isInt(i) + or + exists(TypeTracker t2 | result = trackInt(t2, i).track(t2, t)) + } + + private DataFlow::Node trackInt(int i) { trackInt(TypeTracker::end(), i).flowsTo(result) } + + class PotentialResponseNode extends DataFlow::ArrayLiteralNode { + // [status, headers, body] + PotentialResponseNode() { this.getNumberOfArguments() = 3 } + + /** + * Gets an HTTP status code that may be returned in this response. + */ + int getAStatusCode() { this.getElement(0) = trackInt(result) } + + /** Gets the headers returned with this response. */ + DataFlow::Node getHeaders() { result = this.getElement(1) } + + /** Gets the body of this response. */ + DataFlow::Node getBody() { result = this.getElement(2) } + } +} + +module Public { + bindingset[headerName] + private DataFlow::Node getHeaderValue(ResponseNode resp, string headerName) { + exists(DataFlow::Node headers | headers = resp.getHeaders() | + // set via `headers.=` + exists( + DataFlow::CallNode contentTypeAssignment, Assignment assignment, + DataFlow::PostUpdateNode postUpdateHeaders + | + contentTypeAssignment.getMethodName() = headerName.replaceAll("-", "_").toLowerCase() + "=" and + assignment = + contentTypeAssignment.getArgument(0).(DataFlow::OperationNode).asOperationAstNode() and + postUpdateHeaders.(DataFlow::LocalSourceNode).flowsTo(headers) and + postUpdateHeaders.getPreUpdateNode() = contentTypeAssignment.getReceiver() + | + result.asExpr().getExpr() = assignment.getRightOperand() + ) + or + // set within a hash + exists(DataFlow::HashLiteralNode headersHash | headersHash.flowsTo(headers) | + result = + headersHash + .getElementFromKey(any(ConstantValue v | + v.getStringlikeValue().toLowerCase() = headerName.toLowerCase() + )) + ) + ) + } + + /** A `DataFlow::Node` returned from a rack request. */ + class ResponseNode extends Private::PotentialResponseNode, Http::Server::HttpResponse::Range { + ResponseNode() { this = any(A::App::AppCandidate app).getResponse() } + + override DataFlow::Node getBody() { result = this.getElement(2) } + + override DataFlow::Node getMimetypeOrContentTypeArg() { + result = getHeaderValue(this, "content-type") + } + + // TODO + override string getMimetypeDefault() { none() } + } + + class RedirectResponse extends ResponseNode, Http::Server::HttpRedirectResponse::Range { + RedirectResponse() { this.getAStatusCode() = [300, 301, 302, 303, 307, 308] } + + override DataFlow::Node getRedirectLocation() { result = getHeaderValue(this, "location") } + } +} diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql index b4299d9d6f9..8e0bcee4244 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql @@ -2,20 +2,26 @@ private import codeql.ruby.AST private import codeql.ruby.frameworks.Rack private import codeql.ruby.DataFlow -query predicate rackApps(Rack::AppCandidate c, DataFlow::ParameterNode env) { env = c.getEnv() } +query predicate rackApps(Rack::App::AppCandidate c, DataFlow::ParameterNode env) { + env = c.getEnv() +} -query predicate rackResponseStatusCodes(Rack::ResponseNode resp, string status) { +query predicate rackResponseStatusCodes(Rack::Response::ResponseNode resp, string status) { if exists(resp.getAStatusCode()) then status = resp.getAStatusCode().toString() else status = "" } -query predicate rackResponseContentTypes(Rack::ResponseNode resp, DataFlow::Node contentType) { +query predicate rackResponseContentTypes( + Rack::Response::ResponseNode resp, DataFlow::Node contentType +) { contentType = resp.getMimetypeOrContentTypeArg() } -query predicate mimetypeCalls(Rack::MimetypeCall c, string mimetype) { mimetype = c.getMimeType() } +query predicate mimetypeCalls(Rack::Mime::MimetypeCall c, string mimetype) { + mimetype = c.getMimeType() +} -query predicate redirectResponses(Rack::RedirectResponse resp, DataFlow::Node location) { +query predicate redirectResponses(Rack::Response::RedirectResponse resp, DataFlow::Node location) { location = resp.getRedirectLocation() } From 19664879c877f61630525ce287f115778b1c5732 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 25 May 2023 14:18:09 +0100 Subject: [PATCH 021/364] ruby: slightly expand a TODO --- ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll index f7fb1d31177..c5d5b197382 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll @@ -72,7 +72,7 @@ module Public { result = getHeaderValue(this, "content-type") } - // TODO + // TODO: is there a sensible value for this? override string getMimetypeDefault() { none() } } From 4905a70e21271fe2c7ffabf63173ccf979b01207 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 25 May 2023 14:18:51 +0100 Subject: [PATCH 022/364] Ruby: update rack test output --- .../frameworks/rack/Rack.expected | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.expected b/ruby/ql/test/library-tests/frameworks/rack/Rack.expected index 23fec9a8266..157168f0bd8 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.expected +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.expected @@ -1,12 +1,21 @@ rackApps -| rack.rb:1:1:9:3 | HelloWorld | rack.rb:2:12:2:14 | env | -| rack.rb:11:1:20:3 | Proxy | rack.rb:16:12:16:18 | the_env | -| rack.rb:22:1:35:3 | Logger | rack.rb:28:12:28:14 | env | -| rack.rb:49:1:65:3 | Baz | rack.rb:50:12:50:14 | env | +| rack.rb:1:1:10:3 | HelloWorld | rack.rb:2:12:2:14 | env | +| rack.rb:12:1:22:3 | Proxy | rack.rb:17:12:17:18 | the_env | +| rack.rb:24:1:37:3 | Logger | rack.rb:30:12:30:14 | env | +| rack.rb:39:1:45:3 | Redirector | rack.rb:40:12:40:14 | env | +| rack.rb:59:1:75:3 | Baz | rack.rb:60:12:60:14 | env | rackResponseStatusCodes -| rack.rb:7:5:7:63 | call to [] | 200 | -| rack.rb:7:5:7:63 | call to [] | 500 | -| rack.rb:18:5:18:27 | call to [] | | -| rack.rb:33:5:33:26 | call to [] | | -| rack.rb:56:7:56:22 | call to [] | 200 | -| rack.rb:63:5:63:21 | call to [] | 400 | +| rack.rb:8:5:8:38 | call to [] | 200 | +| rack.rb:8:5:8:38 | call to [] | 500 | +| rack.rb:20:5:20:27 | call to [] | | +| rack.rb:35:5:35:26 | call to [] | | +| rack.rb:43:5:43:45 | call to [] | 302 | +| rack.rb:66:7:66:22 | call to [] | 200 | +| rack.rb:73:5:73:21 | call to [] | 400 | +rackResponseContentTypes +| rack.rb:8:5:8:38 | call to [] | rack.rb:7:34:7:45 | "text/plain" | +| rack.rb:20:5:20:27 | call to [] | rack.rb:19:28:19:54 | call to mime_type | +mimetypeCalls +| rack.rb:19:28:19:54 | call to mime_type | application/x-gzip | +redirectResponses +| rack.rb:43:5:43:45 | call to [] | rack.rb:42:30:42:40 | "/foo.html" | From 40da7d45c2c127045ddc94fa98d9523d57a1d7af Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 25 May 2023 14:20:55 +0100 Subject: [PATCH 023/364] ruby: make a predicate private --- ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll index 502fe72fa51..df09146c315 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll @@ -1,7 +1,7 @@ private import codeql.ruby.ApiGraphs private import codeql.ruby.DataFlow -predicate mimeTypeMatches(string ext, string mimeType) { +private predicate mimeTypeMatches(string ext, string mimeType) { ext = ".123" and mimeType = "application/vnd.lotus-1-2-3" or ext = ".3dml" and mimeType = "text/vnd.in3d.3dml" From 24635df1a363c2685fb4e6be1a79bff322922921 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 25 May 2023 14:21:45 +0100 Subject: [PATCH 024/364] ruby: add some qldoc for rack --- ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll | 3 +++ ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll | 3 +++ ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll index 7dbd7c7a840..78666b7fe1d 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll @@ -14,6 +14,9 @@ private DataFlow::Node trackRackResponse(RP::PotentialResponseNode n) { trackRackResponse(TypeTracker::end(), n).flowsTo(result) } +/** + * Provides modeling for Rack applications. + */ module App { /** * A class that may be a rack application. diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll index df09146c315..d40895a2f13 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll @@ -1287,6 +1287,9 @@ private predicate mimeTypeMatches(string ext, string mimeType) { ext = ".zmm" and mimeType = "application/vnd.handheld-entertainment+xml" } +/** + * Provides modeling for the `Response` component of the `Rack` library. + */ module Mime { class MimetypeCall extends DataFlow::CallNode { MimetypeCall() { diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll index c5d5b197382..4cb3e99c639 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll @@ -6,6 +6,7 @@ private import codeql.ruby.DataFlow private import codeql.ruby.typetracking.TypeTracker private import App as A +/** Contains implementation details for modelling `Rack::Response`. */ module Private { private DataFlow::LocalSourceNode trackInt(TypeTracker t, int i) { t.start() and @@ -33,6 +34,9 @@ module Private { } } +/** + * Provides modeling for the `Response` component of the `Rack` library. + */ module Public { bindingset[headerName] private DataFlow::Node getHeaderValue(ResponseNode resp, string headerName) { From 23e22799a9fe0c65a6a8da4cf64d3de806f1279a Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 26 May 2023 11:38:32 +0100 Subject: [PATCH 025/364] ruby: rack - modelling -> modeling --- ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll index 4cb3e99c639..65322dbac05 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll @@ -6,7 +6,7 @@ private import codeql.ruby.DataFlow private import codeql.ruby.typetracking.TypeTracker private import App as A -/** Contains implementation details for modelling `Rack::Response`. */ +/** Contains implementation details for modeling `Rack::Response`. */ module Private { private DataFlow::LocalSourceNode trackInt(TypeTracker t, int i) { t.start() and From b62a02f0ad38682d7fd1550484aae6d0dd3f997e Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 26 May 2023 11:39:59 +0100 Subject: [PATCH 026/364] ruby: remove unused field --- ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll index c076d6d6698..f995bc5af44 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll @@ -1280,9 +1280,7 @@ class HashLiteralNode extends LocalSourceNode, ExprNode { * explicit calls. */ class ArrayLiteralNode extends LocalSourceNode, CallNode { - private CfgNodes::ExprNodes::ArrayLiteralCfgNode arrayNode; - - ArrayLiteralNode() { super.getExprNode() = arrayNode } + ArrayLiteralNode() { super.getExprNode() instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode } /** * Gets an element of the array. From df4d156a36489ab02f15eb8a2c1ae07dee097ad4 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 1 Jun 2023 11:28:12 -0400 Subject: [PATCH 027/364] C++: remove unneeded exists variables --- .../Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql index 0f8609c3c43..646044bc4f9 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql @@ -146,12 +146,12 @@ module ArrayAddressToDerefConfig implements DataFlow::StateConfigSig { predicate isAdditionalFlowStep( DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2 ) { - exists(PointerArithmeticInstruction pai, Variable v, int size, int delta | + exists(PointerArithmeticInstruction pai, Variable v | state1 = TArray(v) and state2 = TOverflowArithmetic(pai) and pai.getLeft() = node1.asInstruction() and node2.asInstruction() = pai and - pointerArithOverflow(pai, v, size, _, delta) + pointerArithOverflow(pai, v, _, _, _) ) } } From c9c93ca701b64095507b7be45494dd20145b668f Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 1 Jun 2023 11:37:52 -0400 Subject: [PATCH 028/364] C++: test for strncmp false positives --- .../ConstantSizeArrayOffByOne.expected | 10 ++++++++++ .../Security/CWE/CWE-193/constant-size/test.cpp | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected index 831280a015e..88e32ccf921 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected @@ -12,6 +12,10 @@ edges | test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p | | test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf | | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | +| test.cpp:134:25:134:27 | arr | test.cpp:136:9:136:16 | ... += ... | +| test.cpp:136:9:136:16 | ... += ... | test.cpp:138:13:138:15 | arr | +| test.cpp:143:18:143:21 | asdf | test.cpp:134:25:134:27 | arr | +| test.cpp:143:18:143:21 | asdf | test.cpp:143:18:143:21 | asdf | nodes | test.cpp:35:5:35:22 | access to array | semmle.label | access to array | | test.cpp:35:10:35:12 | buf | semmle.label | buf | @@ -36,6 +40,11 @@ nodes | test.cpp:79:32:79:34 | buf | semmle.label | buf | | test.cpp:128:9:128:11 | arr | semmle.label | arr | | test.cpp:128:9:128:14 | access to array | semmle.label | access to array | +| test.cpp:134:25:134:27 | arr | semmle.label | arr | +| test.cpp:136:9:136:16 | ... += ... | semmle.label | ... += ... | +| test.cpp:138:13:138:15 | arr | semmle.label | arr | +| test.cpp:143:18:143:21 | asdf | semmle.label | asdf | +| test.cpp:143:18:143:21 | asdf | semmle.label | asdf | subpaths #select | test.cpp:35:5:35:22 | PointerAdd: access to array | test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:35:5:35:26 | Store: ... = ... | write | @@ -48,3 +57,4 @@ subpaths | test.cpp:72:5:72:15 | PointerAdd: access to array | test.cpp:79:32:79:34 | buf | test.cpp:72:5:72:15 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:72:5:72:19 | Store: ... = ... | write | | test.cpp:77:27:77:44 | PointerAdd: access to array | test.cpp:77:32:77:34 | buf | test.cpp:66:32:66:32 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write | | test.cpp:128:9:128:14 | PointerAdd: access to array | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:125:11:125:13 | arr | arr | test.cpp:128:9:128:18 | Store: ... = ... | write | +| test.cpp:136:9:136:16 | PointerAdd: ... += ... | test.cpp:143:18:143:21 | asdf | test.cpp:138:13:138:15 | arr | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:142:10:142:13 | asdf | asdf | test.cpp:138:12:138:15 | Load: * ... | read | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp index 64b32b9814e..f799518f6ec 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp @@ -85,7 +85,7 @@ void testCharIndex(BigArray *arr) { char *charBuf = (char*) arr->buf; charBuf[MAX_SIZE_BYTES - 1] = 0; // GOOD - charBuf[MAX_SIZE_BYTES] = 0; // BAD [FALSE NEGATIVE] + charBuf[MAX_SIZE_BYTES] = 0; // BAD } void testEqRefinement() { @@ -128,3 +128,17 @@ void testStackAllocated() { arr[i] = 0; // BAD } } + +int strncmp(const char*, const char*, int); + +char testStrncmp2(char *arr) { + if(strncmp(arr, "", 6) == 0) { + arr += 6; + } + return *arr; // GOOD [FALSE POSITIVE] +} + +void testStrncmp1() { + char asdf[5]; + testStrncmp2(asdf); +} From e24e3a61150307a252098153a377046e4412088a Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Tue, 30 May 2023 18:39:14 -0400 Subject: [PATCH 029/364] JS/Python/Ruby: add getInvalidModelKind as experiment --- .../data/internal/ApiGraphModels.qll | 20 +++++++++++++++++++ .../data/internal/ApiGraphModels.qll | 20 +++++++++++++++++++ .../data/internal/ApiGraphModels.qll | 20 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index 227f4ea22fb..e08c4d00932 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -654,6 +654,23 @@ module ModelOutput { import Cached import Specific::ModelOutputSpecific + private string getInvalidModelKind() { + exists(string kind | sinkModel(_, _, kind) | + not kind = + [ + "request-forgery", "jndi-injection", "ldap-injection", "sql-injection", "log-injection", + "mvel-injection", "xpath-injection", "groovy-injection", "html-injection", "js-injection", + "ognl-injection", "intent-redirection", "pending-intents", "url-redirection", + "path-injection", "file-content-store", "hostname-verification", "response-splitting", + "information-leak", "xslt-injection", "jexl-injection", "bean-validation", + "template-injection", "fragment-injection", "command-injection" + ] and + not kind.matches("credentials-%") and + not kind.matches("test-%") and + result = "Invalid kind \"" + kind + "\" in sink model." + ) + } + /** * Gets an error message relating to an invalid CSV row in a model. */ @@ -698,5 +715,8 @@ module ModelOutput { not isValidNoArgumentTokenInIdentifyingAccessPath(token.getName()) and result = "Invalid token '" + token + "' is missing its arguments, in access path: " + path ) + or + // Check for valid model kinds + result = getInvalidModelKind() } } diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index 227f4ea22fb..e08c4d00932 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -654,6 +654,23 @@ module ModelOutput { import Cached import Specific::ModelOutputSpecific + private string getInvalidModelKind() { + exists(string kind | sinkModel(_, _, kind) | + not kind = + [ + "request-forgery", "jndi-injection", "ldap-injection", "sql-injection", "log-injection", + "mvel-injection", "xpath-injection", "groovy-injection", "html-injection", "js-injection", + "ognl-injection", "intent-redirection", "pending-intents", "url-redirection", + "path-injection", "file-content-store", "hostname-verification", "response-splitting", + "information-leak", "xslt-injection", "jexl-injection", "bean-validation", + "template-injection", "fragment-injection", "command-injection" + ] and + not kind.matches("credentials-%") and + not kind.matches("test-%") and + result = "Invalid kind \"" + kind + "\" in sink model." + ) + } + /** * Gets an error message relating to an invalid CSV row in a model. */ @@ -698,5 +715,8 @@ module ModelOutput { not isValidNoArgumentTokenInIdentifyingAccessPath(token.getName()) and result = "Invalid token '" + token + "' is missing its arguments, in access path: " + path ) + or + // Check for valid model kinds + result = getInvalidModelKind() } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index 227f4ea22fb..e08c4d00932 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -654,6 +654,23 @@ module ModelOutput { import Cached import Specific::ModelOutputSpecific + private string getInvalidModelKind() { + exists(string kind | sinkModel(_, _, kind) | + not kind = + [ + "request-forgery", "jndi-injection", "ldap-injection", "sql-injection", "log-injection", + "mvel-injection", "xpath-injection", "groovy-injection", "html-injection", "js-injection", + "ognl-injection", "intent-redirection", "pending-intents", "url-redirection", + "path-injection", "file-content-store", "hostname-verification", "response-splitting", + "information-leak", "xslt-injection", "jexl-injection", "bean-validation", + "template-injection", "fragment-injection", "command-injection" + ] and + not kind.matches("credentials-%") and + not kind.matches("test-%") and + result = "Invalid kind \"" + kind + "\" in sink model." + ) + } + /** * Gets an error message relating to an invalid CSV row in a model. */ @@ -698,5 +715,8 @@ module ModelOutput { not isValidNoArgumentTokenInIdentifyingAccessPath(token.getName()) and result = "Invalid token '" + token + "' is missing its arguments, in access path: " + path ) + or + // Check for valid model kinds + result = getInvalidModelKind() } } From 869f820fcfc38b2c22d83e20ec442f7e15e432e8 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Tue, 30 May 2023 18:40:05 -0400 Subject: [PATCH 030/364] Shared: add 'SharedModelValidation' file as experiment --- config/identical-files.json | 9 ++++++ .../csharp/dataflow/SharedModelValidation.qll | 30 +++++++++++++++++++ .../go/dataflow/SharedModelValidation.qll | 30 +++++++++++++++++++ .../java/dataflow/SharedModelValidation.qll | 30 +++++++++++++++++++ .../data/internal/SharedModelValidation.qll | 30 +++++++++++++++++++ .../data/internal/SharedModelValidation.qll | 30 +++++++++++++++++++ .../data/internal/SharedModelValidation.qll | 30 +++++++++++++++++++ .../swift/dataflow/SharedModelValidation.qll | 30 +++++++++++++++++++ 8 files changed, 219 insertions(+) create mode 100644 csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll create mode 100644 go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll create mode 100644 java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll create mode 100644 javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll create mode 100644 python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll create mode 100644 swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll diff --git a/config/identical-files.json b/config/identical-files.json index 3c16c953129..cdda39b041a 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -598,5 +598,14 @@ "EncryptionKeySizes Python/Java": [ "python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll", "java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll" + ], + "SharedModelValidation Java/C#/Go/JS/Python/Ruby/Swift (C++ is problematic for now)": [ + "java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll", + "csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll", + "go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll", + "swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll", + "javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll", + "python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll", + "ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll" ] } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll new file mode 100644 index 00000000000..948b361e4ad --- /dev/null +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll @@ -0,0 +1,30 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes for validating kinds in models as data rows. + * Such that we can share this logic across our CodeQL analysis of different languages. + */ +class ValidSinkKind extends string { + ValidSinkKind() { + this = + [ + // shared ALL languages + "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", + "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", + "file-content-store", "hostname-verification", "response-splitting", "information-leak", + "xslt-injection", "template-injection", "fragment-injection", "command-injection", + "unsafe-deserialization", "xxe", "database-store", "format-string", + // .matches("credentials-%"), .matches("regex-use%")" + // shared MOST languages + "code-injection", // .matches("encryption-%"), + // Java only + "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", + "bean-validation", "intent-redirection", "pending-intents", + // JS only + "mongodb.sink", + // Swift only + "preferences-store", "transmission", "predicate-injection", "webview-fetch", + "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + ] + } +} diff --git a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll new file mode 100644 index 00000000000..948b361e4ad --- /dev/null +++ b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll @@ -0,0 +1,30 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes for validating kinds in models as data rows. + * Such that we can share this logic across our CodeQL analysis of different languages. + */ +class ValidSinkKind extends string { + ValidSinkKind() { + this = + [ + // shared ALL languages + "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", + "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", + "file-content-store", "hostname-verification", "response-splitting", "information-leak", + "xslt-injection", "template-injection", "fragment-injection", "command-injection", + "unsafe-deserialization", "xxe", "database-store", "format-string", + // .matches("credentials-%"), .matches("regex-use%")" + // shared MOST languages + "code-injection", // .matches("encryption-%"), + // Java only + "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", + "bean-validation", "intent-redirection", "pending-intents", + // JS only + "mongodb.sink", + // Swift only + "preferences-store", "transmission", "predicate-injection", "webview-fetch", + "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + ] + } +} diff --git a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll new file mode 100644 index 00000000000..948b361e4ad --- /dev/null +++ b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll @@ -0,0 +1,30 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes for validating kinds in models as data rows. + * Such that we can share this logic across our CodeQL analysis of different languages. + */ +class ValidSinkKind extends string { + ValidSinkKind() { + this = + [ + // shared ALL languages + "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", + "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", + "file-content-store", "hostname-verification", "response-splitting", "information-leak", + "xslt-injection", "template-injection", "fragment-injection", "command-injection", + "unsafe-deserialization", "xxe", "database-store", "format-string", + // .matches("credentials-%"), .matches("regex-use%")" + // shared MOST languages + "code-injection", // .matches("encryption-%"), + // Java only + "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", + "bean-validation", "intent-redirection", "pending-intents", + // JS only + "mongodb.sink", + // Swift only + "preferences-store", "transmission", "predicate-injection", "webview-fetch", + "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + ] + } +} diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll new file mode 100644 index 00000000000..948b361e4ad --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll @@ -0,0 +1,30 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes for validating kinds in models as data rows. + * Such that we can share this logic across our CodeQL analysis of different languages. + */ +class ValidSinkKind extends string { + ValidSinkKind() { + this = + [ + // shared ALL languages + "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", + "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", + "file-content-store", "hostname-verification", "response-splitting", "information-leak", + "xslt-injection", "template-injection", "fragment-injection", "command-injection", + "unsafe-deserialization", "xxe", "database-store", "format-string", + // .matches("credentials-%"), .matches("regex-use%")" + // shared MOST languages + "code-injection", // .matches("encryption-%"), + // Java only + "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", + "bean-validation", "intent-redirection", "pending-intents", + // JS only + "mongodb.sink", + // Swift only + "preferences-store", "transmission", "predicate-injection", "webview-fetch", + "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + ] + } +} diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll new file mode 100644 index 00000000000..948b361e4ad --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll @@ -0,0 +1,30 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes for validating kinds in models as data rows. + * Such that we can share this logic across our CodeQL analysis of different languages. + */ +class ValidSinkKind extends string { + ValidSinkKind() { + this = + [ + // shared ALL languages + "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", + "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", + "file-content-store", "hostname-verification", "response-splitting", "information-leak", + "xslt-injection", "template-injection", "fragment-injection", "command-injection", + "unsafe-deserialization", "xxe", "database-store", "format-string", + // .matches("credentials-%"), .matches("regex-use%")" + // shared MOST languages + "code-injection", // .matches("encryption-%"), + // Java only + "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", + "bean-validation", "intent-redirection", "pending-intents", + // JS only + "mongodb.sink", + // Swift only + "preferences-store", "transmission", "predicate-injection", "webview-fetch", + "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + ] + } +} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll new file mode 100644 index 00000000000..948b361e4ad --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll @@ -0,0 +1,30 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes for validating kinds in models as data rows. + * Such that we can share this logic across our CodeQL analysis of different languages. + */ +class ValidSinkKind extends string { + ValidSinkKind() { + this = + [ + // shared ALL languages + "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", + "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", + "file-content-store", "hostname-verification", "response-splitting", "information-leak", + "xslt-injection", "template-injection", "fragment-injection", "command-injection", + "unsafe-deserialization", "xxe", "database-store", "format-string", + // .matches("credentials-%"), .matches("regex-use%")" + // shared MOST languages + "code-injection", // .matches("encryption-%"), + // Java only + "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", + "bean-validation", "intent-redirection", "pending-intents", + // JS only + "mongodb.sink", + // Swift only + "preferences-store", "transmission", "predicate-injection", "webview-fetch", + "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + ] + } +} diff --git a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll new file mode 100644 index 00000000000..948b361e4ad --- /dev/null +++ b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll @@ -0,0 +1,30 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes for validating kinds in models as data rows. + * Such that we can share this logic across our CodeQL analysis of different languages. + */ +class ValidSinkKind extends string { + ValidSinkKind() { + this = + [ + // shared ALL languages + "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", + "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", + "file-content-store", "hostname-verification", "response-splitting", "information-leak", + "xslt-injection", "template-injection", "fragment-injection", "command-injection", + "unsafe-deserialization", "xxe", "database-store", "format-string", + // .matches("credentials-%"), .matches("regex-use%")" + // shared MOST languages + "code-injection", // .matches("encryption-%"), + // Java only + "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", + "bean-validation", "intent-redirection", "pending-intents", + // JS only + "mongodb.sink", + // Swift only + "preferences-store", "transmission", "predicate-injection", "webview-fetch", + "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + ] + } +} From ddb5d92ef8a854711eb35ff6cef90963adfd412d Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Tue, 30 May 2023 19:01:27 -0400 Subject: [PATCH 031/364] Shared: add source, summary, and neutral shared valid kinds --- .../csharp/dataflow/SharedModelValidation.qll | 35 +++++++++++++++++++ .../go/dataflow/SharedModelValidation.qll | 35 +++++++++++++++++++ .../java/dataflow/SharedModelValidation.qll | 35 +++++++++++++++++++ .../data/internal/SharedModelValidation.qll | 35 +++++++++++++++++++ .../data/internal/SharedModelValidation.qll | 35 +++++++++++++++++++ .../data/internal/SharedModelValidation.qll | 35 +++++++++++++++++++ .../swift/dataflow/SharedModelValidation.qll | 35 +++++++++++++++++++ 7 files changed, 245 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll index 948b361e4ad..8178dcf13d3 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll @@ -4,6 +4,8 @@ * Provides classes for validating kinds in models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ + +/** A valid models-as-data sink kind. */ class ValidSinkKind extends string { ValidSinkKind() { this = @@ -28,3 +30,36 @@ class ValidSinkKind extends string { ] } } + +/** A valid models-as-data source kind. */ +class ValidSourceKind extends string { + ValidSourceKind() { + this = + [ + // shared ALL languages + "remote", "local" + ] + } +} + +/** A valid models-as-data summary kind. */ +class ValidSummaryKind extends string { + ValidSummaryKind() { + this = + [ + // shared ALL languages + "taint", "value" + ] + } +} + +/** A valid models-as-data neutral kind. */ +class ValidNeutralKind extends string { + ValidNeutralKind() { + this = + [ + // shared ALL languages + "summary", "source", "sink" + ] + } +} diff --git a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll index 948b361e4ad..8178dcf13d3 100644 --- a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll +++ b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll @@ -4,6 +4,8 @@ * Provides classes for validating kinds in models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ + +/** A valid models-as-data sink kind. */ class ValidSinkKind extends string { ValidSinkKind() { this = @@ -28,3 +30,36 @@ class ValidSinkKind extends string { ] } } + +/** A valid models-as-data source kind. */ +class ValidSourceKind extends string { + ValidSourceKind() { + this = + [ + // shared ALL languages + "remote", "local" + ] + } +} + +/** A valid models-as-data summary kind. */ +class ValidSummaryKind extends string { + ValidSummaryKind() { + this = + [ + // shared ALL languages + "taint", "value" + ] + } +} + +/** A valid models-as-data neutral kind. */ +class ValidNeutralKind extends string { + ValidNeutralKind() { + this = + [ + // shared ALL languages + "summary", "source", "sink" + ] + } +} diff --git a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll index 948b361e4ad..8178dcf13d3 100644 --- a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll +++ b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll @@ -4,6 +4,8 @@ * Provides classes for validating kinds in models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ + +/** A valid models-as-data sink kind. */ class ValidSinkKind extends string { ValidSinkKind() { this = @@ -28,3 +30,36 @@ class ValidSinkKind extends string { ] } } + +/** A valid models-as-data source kind. */ +class ValidSourceKind extends string { + ValidSourceKind() { + this = + [ + // shared ALL languages + "remote", "local" + ] + } +} + +/** A valid models-as-data summary kind. */ +class ValidSummaryKind extends string { + ValidSummaryKind() { + this = + [ + // shared ALL languages + "taint", "value" + ] + } +} + +/** A valid models-as-data neutral kind. */ +class ValidNeutralKind extends string { + ValidNeutralKind() { + this = + [ + // shared ALL languages + "summary", "source", "sink" + ] + } +} diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll index 948b361e4ad..8178dcf13d3 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll @@ -4,6 +4,8 @@ * Provides classes for validating kinds in models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ + +/** A valid models-as-data sink kind. */ class ValidSinkKind extends string { ValidSinkKind() { this = @@ -28,3 +30,36 @@ class ValidSinkKind extends string { ] } } + +/** A valid models-as-data source kind. */ +class ValidSourceKind extends string { + ValidSourceKind() { + this = + [ + // shared ALL languages + "remote", "local" + ] + } +} + +/** A valid models-as-data summary kind. */ +class ValidSummaryKind extends string { + ValidSummaryKind() { + this = + [ + // shared ALL languages + "taint", "value" + ] + } +} + +/** A valid models-as-data neutral kind. */ +class ValidNeutralKind extends string { + ValidNeutralKind() { + this = + [ + // shared ALL languages + "summary", "source", "sink" + ] + } +} diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll index 948b361e4ad..8178dcf13d3 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll @@ -4,6 +4,8 @@ * Provides classes for validating kinds in models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ + +/** A valid models-as-data sink kind. */ class ValidSinkKind extends string { ValidSinkKind() { this = @@ -28,3 +30,36 @@ class ValidSinkKind extends string { ] } } + +/** A valid models-as-data source kind. */ +class ValidSourceKind extends string { + ValidSourceKind() { + this = + [ + // shared ALL languages + "remote", "local" + ] + } +} + +/** A valid models-as-data summary kind. */ +class ValidSummaryKind extends string { + ValidSummaryKind() { + this = + [ + // shared ALL languages + "taint", "value" + ] + } +} + +/** A valid models-as-data neutral kind. */ +class ValidNeutralKind extends string { + ValidNeutralKind() { + this = + [ + // shared ALL languages + "summary", "source", "sink" + ] + } +} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll index 948b361e4ad..8178dcf13d3 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll @@ -4,6 +4,8 @@ * Provides classes for validating kinds in models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ + +/** A valid models-as-data sink kind. */ class ValidSinkKind extends string { ValidSinkKind() { this = @@ -28,3 +30,36 @@ class ValidSinkKind extends string { ] } } + +/** A valid models-as-data source kind. */ +class ValidSourceKind extends string { + ValidSourceKind() { + this = + [ + // shared ALL languages + "remote", "local" + ] + } +} + +/** A valid models-as-data summary kind. */ +class ValidSummaryKind extends string { + ValidSummaryKind() { + this = + [ + // shared ALL languages + "taint", "value" + ] + } +} + +/** A valid models-as-data neutral kind. */ +class ValidNeutralKind extends string { + ValidNeutralKind() { + this = + [ + // shared ALL languages + "summary", "source", "sink" + ] + } +} diff --git a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll index 948b361e4ad..8178dcf13d3 100644 --- a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll +++ b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll @@ -4,6 +4,8 @@ * Provides classes for validating kinds in models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ + +/** A valid models-as-data sink kind. */ class ValidSinkKind extends string { ValidSinkKind() { this = @@ -28,3 +30,36 @@ class ValidSinkKind extends string { ] } } + +/** A valid models-as-data source kind. */ +class ValidSourceKind extends string { + ValidSourceKind() { + this = + [ + // shared ALL languages + "remote", "local" + ] + } +} + +/** A valid models-as-data summary kind. */ +class ValidSummaryKind extends string { + ValidSummaryKind() { + this = + [ + // shared ALL languages + "taint", "value" + ] + } +} + +/** A valid models-as-data neutral kind. */ +class ValidNeutralKind extends string { + ValidNeutralKind() { + this = + [ + // shared ALL languages + "summary", "source", "sink" + ] + } +} From 0ab1848b70803675303044a3fdaae5f72f156ca3 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Tue, 30 May 2023 19:04:15 -0400 Subject: [PATCH 032/364] JS/Python/Ruby: use 'SharedModelValidation' file --- .../data/internal/ApiGraphModels.qll | 22 +++++++++++-------- .../data/internal/ApiGraphModels.qll | 22 +++++++++++-------- .../data/internal/ApiGraphModels.qll | 22 +++++++++++-------- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index e08c4d00932..4799f75937e 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -653,22 +653,26 @@ module ModelOutput { import Cached import Specific::ModelOutputSpecific + private import SharedModelValidation private string getInvalidModelKind() { + exists(string kind | summaryModel(_, _, _, _, kind) | + not kind instanceof ValidSummaryKind and + result = "Invalid kind \"" + kind + "\" in summary model." + ) + or exists(string kind | sinkModel(_, _, kind) | - not kind = - [ - "request-forgery", "jndi-injection", "ldap-injection", "sql-injection", "log-injection", - "mvel-injection", "xpath-injection", "groovy-injection", "html-injection", "js-injection", - "ognl-injection", "intent-redirection", "pending-intents", "url-redirection", - "path-injection", "file-content-store", "hostname-verification", "response-splitting", - "information-leak", "xslt-injection", "jexl-injection", "bean-validation", - "template-injection", "fragment-injection", "command-injection" - ] and + not kind instanceof ValidSinkKind and not kind.matches("credentials-%") and not kind.matches("test-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) + or + exists(string kind | sourceModel(_, _, kind) | + not kind instanceof ValidSourceKind and + not kind.matches("qltest%") and + result = "Invalid kind \"" + kind + "\" in source model." + ) } /** diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index e08c4d00932..4799f75937e 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -653,22 +653,26 @@ module ModelOutput { import Cached import Specific::ModelOutputSpecific + private import SharedModelValidation private string getInvalidModelKind() { + exists(string kind | summaryModel(_, _, _, _, kind) | + not kind instanceof ValidSummaryKind and + result = "Invalid kind \"" + kind + "\" in summary model." + ) + or exists(string kind | sinkModel(_, _, kind) | - not kind = - [ - "request-forgery", "jndi-injection", "ldap-injection", "sql-injection", "log-injection", - "mvel-injection", "xpath-injection", "groovy-injection", "html-injection", "js-injection", - "ognl-injection", "intent-redirection", "pending-intents", "url-redirection", - "path-injection", "file-content-store", "hostname-verification", "response-splitting", - "information-leak", "xslt-injection", "jexl-injection", "bean-validation", - "template-injection", "fragment-injection", "command-injection" - ] and + not kind instanceof ValidSinkKind and not kind.matches("credentials-%") and not kind.matches("test-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) + or + exists(string kind | sourceModel(_, _, kind) | + not kind instanceof ValidSourceKind and + not kind.matches("qltest%") and + result = "Invalid kind \"" + kind + "\" in source model." + ) } /** diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index e08c4d00932..4799f75937e 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -653,22 +653,26 @@ module ModelOutput { import Cached import Specific::ModelOutputSpecific + private import SharedModelValidation private string getInvalidModelKind() { + exists(string kind | summaryModel(_, _, _, _, kind) | + not kind instanceof ValidSummaryKind and + result = "Invalid kind \"" + kind + "\" in summary model." + ) + or exists(string kind | sinkModel(_, _, kind) | - not kind = - [ - "request-forgery", "jndi-injection", "ldap-injection", "sql-injection", "log-injection", - "mvel-injection", "xpath-injection", "groovy-injection", "html-injection", "js-injection", - "ognl-injection", "intent-redirection", "pending-intents", "url-redirection", - "path-injection", "file-content-store", "hostname-verification", "response-splitting", - "information-leak", "xslt-injection", "jexl-injection", "bean-validation", - "template-injection", "fragment-injection", "command-injection" - ] and + not kind instanceof ValidSinkKind and not kind.matches("credentials-%") and not kind.matches("test-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) + or + exists(string kind | sourceModel(_, _, kind) | + not kind instanceof ValidSourceKind and + not kind.matches("qltest%") and + result = "Invalid kind \"" + kind + "\" in source model." + ) } /** From 79f61cc645bbcfaffc35fed6482b0a08fe33306b Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Fri, 2 Jun 2023 13:54:45 -0400 Subject: [PATCH 033/364] Java/C#/Go/Swift: use 'SharedModelValidation' file --- .../code/csharp/dataflow/ExternalFlow.qll | 15 ++++++---- go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 4 ++- .../code/java/dataflow/ExternalFlow.qll | 29 +++++++++++-------- .../codeql/swift/dataflow/ExternalFlow.qll | 4 ++- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 46a19828a81..902d6f246c9 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -95,6 +95,7 @@ private import internal.DataFlowPublic private import internal.FlowSummaryImpl::Public private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImplSpecific +private import SharedModelValidation /** Holds if a source model exists for the given parameters. */ predicate sourceModel = Extensions::sourceModel/9; @@ -206,24 +207,28 @@ module ModelValidation { private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | - not kind = ["taint", "value"] and + not kind instanceof ValidSummaryKind and + //not kind = ["taint", "value"] and result = "Invalid kind \"" + kind + "\" in summary model." ) or exists(string kind | sinkModel(_, _, _, _, _, _, _, kind, _) | - not kind = - ["code-injection", "sql-injection", "js-injection", "html-injection", "file-content-store"] and + not kind instanceof ValidSinkKind and + // not kind = + // ["code-injection", "sql-injection", "js-injection", "html-injection", "file-content-store"] and not kind.matches("encryption-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) or exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | - not kind = ["local", "remote", "file", "file-write"] and + not kind instanceof ValidSourceKind and + //not kind = ["local", "remote", "file", "file-write"] and result = "Invalid kind \"" + kind + "\" in source model." ) or exists(string kind | neutralModel(_, _, _, _, kind, _) | - not kind = ["summary", "source", "sink"] and + not kind instanceof ValidNeutralKind and + //not kind = ["summary", "source", "sink"] and result = "Invalid kind \"" + kind + "\" in neutral model." ) } diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 0c6ee1c3134..05818ab68c7 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -68,6 +68,7 @@ private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImplSpecific private import internal.AccessPathSyntax private import FlowSummary +private import SharedModelValidation /** * A module importing the frameworks that provide external flow data, @@ -190,7 +191,8 @@ module ModelValidation { private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | - not kind = ["taint", "value"] and + not kind instanceof ValidSummaryKind and + //not kind = ["taint", "value"] and result = "Invalid kind \"" + kind + "\" in summary model." ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index bb8485cd601..b3a128fb4e1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -87,6 +87,7 @@ private import internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific private import internal.AccessPathSyntax private import ExternalFlowExtensions as Extensions private import FlowSummary +private import SharedModelValidation /** * A class for activating additional model rows. @@ -311,20 +312,22 @@ module ModelValidation { private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | - not kind = ["taint", "value"] and + not kind instanceof ValidSummaryKind and + //not kind = ["taint", "value"] and result = "Invalid kind \"" + kind + "\" in summary model." ) or exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | - not kind = - [ - "request-forgery", "jndi-injection", "ldap-injection", "sql-injection", "log-injection", - "mvel-injection", "xpath-injection", "groovy-injection", "html-injection", "js-injection", - "ognl-injection", "intent-redirection", "pending-intents", "url-redirection", - "path-injection", "file-content-store", "hostname-verification", "response-splitting", - "information-leak", "xslt-injection", "jexl-injection", "bean-validation", - "template-injection", "fragment-injection", "command-injection" - ] and + not kind instanceof ValidSinkKind and + // not kind = + // [ + // "request-forgery", "jndi-injection", "ldap-injection", "sql-injection", "log-injection", + // "mvel-injection", "xpath-injection", "groovy-injection", "html-injection", "js-injection", + // "ognl-injection", "intent-redirection", "pending-intents", "url-redirection", + // "path-injection", "file-content-store", "hostname-verification", "response-splitting", + // "information-leak", "xslt-injection", "jexl-injection", "bean-validation", + // "template-injection", "fragment-injection", "command-injection" + // ] and not kind.matches("regex-use%") and not kind.matches("qltest%") and msg = "Invalid kind \"" + kind + "\" in sink model." and @@ -335,13 +338,15 @@ module ModelValidation { ) or exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | - not kind = ["remote", "contentprovider", "android-external-storage-dir"] and + not kind instanceof ValidSourceKind and + // not kind = ["remote", "contentprovider", "android-widget", "android-external-storage-dir"] and not kind.matches("qltest%") and result = "Invalid kind \"" + kind + "\" in source model." ) or exists(string kind | neutralModel(_, _, _, _, kind, _) | - not kind = ["summary", "source", "sink"] and + not kind instanceof ValidNeutralKind and + //not kind = ["summary", "source", "sink"] and result = "Invalid kind \"" + kind + "\" in neutral model." ) } diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index 82daf14a39a..0adc9be7373 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -74,6 +74,7 @@ private import internal.FlowSummaryImpl::Public private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImplSpecific private import FlowSummary as FlowSummary +private import SharedModelValidation /** * A unit class for adding additional source model rows. @@ -266,7 +267,8 @@ module CsvValidation { private string getInvalidModelKind() { exists(string row, string kind | summaryModel(row) | kind = row.splitAt(";", 8) and - not kind = ["taint", "value"] and + not kind instanceof ValidSummaryKind and + //not kind = ["taint", "value"] and result = "Invalid kind \"" + kind + "\" in summary model." ) } From 7317c29eead9417a19d66d148268135fbbcdbf68 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Fri, 2 Jun 2023 16:49:49 -0400 Subject: [PATCH 034/364] Shared: update kind information --- .../csharp/dataflow/SharedModelValidation.qll | 67 ++++++++++++------- .../go/dataflow/SharedModelValidation.qll | 67 ++++++++++++------- .../java/dataflow/SharedModelValidation.qll | 67 ++++++++++++------- .../data/internal/SharedModelValidation.qll | 67 ++++++++++++------- .../data/internal/SharedModelValidation.qll | 67 ++++++++++++------- .../data/internal/SharedModelValidation.qll | 67 ++++++++++++------- .../swift/dataflow/SharedModelValidation.qll | 67 ++++++++++++------- 7 files changed, 308 insertions(+), 161 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll index 8178dcf13d3..5b0105ad554 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll @@ -7,38 +7,57 @@ /** A valid models-as-data sink kind. */ class ValidSinkKind extends string { + bindingset[this] ValidSinkKind() { this = [ - // shared ALL languages - "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", - "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", - "file-content-store", "hostname-verification", "response-splitting", "information-leak", - "xslt-injection", "template-injection", "fragment-injection", "command-injection", - "unsafe-deserialization", "xxe", "database-store", "format-string", - // .matches("credentials-%"), .matches("regex-use%")" - // shared MOST languages - "code-injection", // .matches("encryption-%"), - // Java only - "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", - "bean-validation", "intent-redirection", "pending-intents", - // JS only - "mongodb.sink", - // Swift only - "preferences-store", "transmission", "predicate-injection", "webview-fetch", - "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + // shared + "code-injection", "command-injection", "file-content-store", "html-injection", + "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", + "sql-injection", "url-redirection", + // Java-only currently, but may be shared in the future + "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", + "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", + "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", + "template-injection", "xpath-injection", "xslt-injection", + // JavaScript-only currently, but may be shared in the future + "mongodb.sink", "nosql-injection", "unsafe-deserialization", + // Swift-only currently, but may be shared in the future + "database-store", "format-string", "hash-iteration-count", "predicate-injection", + "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" ] + or + this.matches([ + // shared + "encryption-%", + // Java-only currently, but may be shared in the future + "regex-use%", + // JavaScript-only currently, but may be shared in the future + "credentials-%", + // Swift-only currently, but may be shared in the future + "%string-%length", "weak-hash-input-%" + ]) } } /** A valid models-as-data source kind. */ class ValidSourceKind extends string { + bindingset[this] ValidSourceKind() { this = [ - // shared ALL languages - "remote", "local" + // shared + "local", "remote", + // Java + "android-external-storage-dir", "contentprovider", + // C# + "file", "file-write", + // JavaScript + "database-access-result" ] + or + // Swift + this.matches("%string-%length") } } @@ -47,8 +66,10 @@ class ValidSummaryKind extends string { ValidSummaryKind() { this = [ - // shared ALL languages - "taint", "value" + // shared + "taint", "value", + // JavaScript + "type" ] } } @@ -58,8 +79,8 @@ class ValidNeutralKind extends string { ValidNeutralKind() { this = [ - // shared ALL languages - "summary", "source", "sink" + // Java/C# currently + "sink", "source", "summary" ] } } diff --git a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll index 8178dcf13d3..5b0105ad554 100644 --- a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll +++ b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll @@ -7,38 +7,57 @@ /** A valid models-as-data sink kind. */ class ValidSinkKind extends string { + bindingset[this] ValidSinkKind() { this = [ - // shared ALL languages - "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", - "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", - "file-content-store", "hostname-verification", "response-splitting", "information-leak", - "xslt-injection", "template-injection", "fragment-injection", "command-injection", - "unsafe-deserialization", "xxe", "database-store", "format-string", - // .matches("credentials-%"), .matches("regex-use%")" - // shared MOST languages - "code-injection", // .matches("encryption-%"), - // Java only - "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", - "bean-validation", "intent-redirection", "pending-intents", - // JS only - "mongodb.sink", - // Swift only - "preferences-store", "transmission", "predicate-injection", "webview-fetch", - "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + // shared + "code-injection", "command-injection", "file-content-store", "html-injection", + "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", + "sql-injection", "url-redirection", + // Java-only currently, but may be shared in the future + "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", + "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", + "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", + "template-injection", "xpath-injection", "xslt-injection", + // JavaScript-only currently, but may be shared in the future + "mongodb.sink", "nosql-injection", "unsafe-deserialization", + // Swift-only currently, but may be shared in the future + "database-store", "format-string", "hash-iteration-count", "predicate-injection", + "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" ] + or + this.matches([ + // shared + "encryption-%", + // Java-only currently, but may be shared in the future + "regex-use%", + // JavaScript-only currently, but may be shared in the future + "credentials-%", + // Swift-only currently, but may be shared in the future + "%string-%length", "weak-hash-input-%" + ]) } } /** A valid models-as-data source kind. */ class ValidSourceKind extends string { + bindingset[this] ValidSourceKind() { this = [ - // shared ALL languages - "remote", "local" + // shared + "local", "remote", + // Java + "android-external-storage-dir", "contentprovider", + // C# + "file", "file-write", + // JavaScript + "database-access-result" ] + or + // Swift + this.matches("%string-%length") } } @@ -47,8 +66,10 @@ class ValidSummaryKind extends string { ValidSummaryKind() { this = [ - // shared ALL languages - "taint", "value" + // shared + "taint", "value", + // JavaScript + "type" ] } } @@ -58,8 +79,8 @@ class ValidNeutralKind extends string { ValidNeutralKind() { this = [ - // shared ALL languages - "summary", "source", "sink" + // Java/C# currently + "sink", "source", "summary" ] } } diff --git a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll index 8178dcf13d3..5b0105ad554 100644 --- a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll +++ b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll @@ -7,38 +7,57 @@ /** A valid models-as-data sink kind. */ class ValidSinkKind extends string { + bindingset[this] ValidSinkKind() { this = [ - // shared ALL languages - "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", - "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", - "file-content-store", "hostname-verification", "response-splitting", "information-leak", - "xslt-injection", "template-injection", "fragment-injection", "command-injection", - "unsafe-deserialization", "xxe", "database-store", "format-string", - // .matches("credentials-%"), .matches("regex-use%")" - // shared MOST languages - "code-injection", // .matches("encryption-%"), - // Java only - "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", - "bean-validation", "intent-redirection", "pending-intents", - // JS only - "mongodb.sink", - // Swift only - "preferences-store", "transmission", "predicate-injection", "webview-fetch", - "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + // shared + "code-injection", "command-injection", "file-content-store", "html-injection", + "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", + "sql-injection", "url-redirection", + // Java-only currently, but may be shared in the future + "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", + "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", + "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", + "template-injection", "xpath-injection", "xslt-injection", + // JavaScript-only currently, but may be shared in the future + "mongodb.sink", "nosql-injection", "unsafe-deserialization", + // Swift-only currently, but may be shared in the future + "database-store", "format-string", "hash-iteration-count", "predicate-injection", + "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" ] + or + this.matches([ + // shared + "encryption-%", + // Java-only currently, but may be shared in the future + "regex-use%", + // JavaScript-only currently, but may be shared in the future + "credentials-%", + // Swift-only currently, but may be shared in the future + "%string-%length", "weak-hash-input-%" + ]) } } /** A valid models-as-data source kind. */ class ValidSourceKind extends string { + bindingset[this] ValidSourceKind() { this = [ - // shared ALL languages - "remote", "local" + // shared + "local", "remote", + // Java + "android-external-storage-dir", "contentprovider", + // C# + "file", "file-write", + // JavaScript + "database-access-result" ] + or + // Swift + this.matches("%string-%length") } } @@ -47,8 +66,10 @@ class ValidSummaryKind extends string { ValidSummaryKind() { this = [ - // shared ALL languages - "taint", "value" + // shared + "taint", "value", + // JavaScript + "type" ] } } @@ -58,8 +79,8 @@ class ValidNeutralKind extends string { ValidNeutralKind() { this = [ - // shared ALL languages - "summary", "source", "sink" + // Java/C# currently + "sink", "source", "summary" ] } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll index 8178dcf13d3..5b0105ad554 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll @@ -7,38 +7,57 @@ /** A valid models-as-data sink kind. */ class ValidSinkKind extends string { + bindingset[this] ValidSinkKind() { this = [ - // shared ALL languages - "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", - "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", - "file-content-store", "hostname-verification", "response-splitting", "information-leak", - "xslt-injection", "template-injection", "fragment-injection", "command-injection", - "unsafe-deserialization", "xxe", "database-store", "format-string", - // .matches("credentials-%"), .matches("regex-use%")" - // shared MOST languages - "code-injection", // .matches("encryption-%"), - // Java only - "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", - "bean-validation", "intent-redirection", "pending-intents", - // JS only - "mongodb.sink", - // Swift only - "preferences-store", "transmission", "predicate-injection", "webview-fetch", - "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + // shared + "code-injection", "command-injection", "file-content-store", "html-injection", + "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", + "sql-injection", "url-redirection", + // Java-only currently, but may be shared in the future + "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", + "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", + "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", + "template-injection", "xpath-injection", "xslt-injection", + // JavaScript-only currently, but may be shared in the future + "mongodb.sink", "nosql-injection", "unsafe-deserialization", + // Swift-only currently, but may be shared in the future + "database-store", "format-string", "hash-iteration-count", "predicate-injection", + "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" ] + or + this.matches([ + // shared + "encryption-%", + // Java-only currently, but may be shared in the future + "regex-use%", + // JavaScript-only currently, but may be shared in the future + "credentials-%", + // Swift-only currently, but may be shared in the future + "%string-%length", "weak-hash-input-%" + ]) } } /** A valid models-as-data source kind. */ class ValidSourceKind extends string { + bindingset[this] ValidSourceKind() { this = [ - // shared ALL languages - "remote", "local" + // shared + "local", "remote", + // Java + "android-external-storage-dir", "contentprovider", + // C# + "file", "file-write", + // JavaScript + "database-access-result" ] + or + // Swift + this.matches("%string-%length") } } @@ -47,8 +66,10 @@ class ValidSummaryKind extends string { ValidSummaryKind() { this = [ - // shared ALL languages - "taint", "value" + // shared + "taint", "value", + // JavaScript + "type" ] } } @@ -58,8 +79,8 @@ class ValidNeutralKind extends string { ValidNeutralKind() { this = [ - // shared ALL languages - "summary", "source", "sink" + // Java/C# currently + "sink", "source", "summary" ] } } diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll index 8178dcf13d3..5b0105ad554 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll @@ -7,38 +7,57 @@ /** A valid models-as-data sink kind. */ class ValidSinkKind extends string { + bindingset[this] ValidSinkKind() { this = [ - // shared ALL languages - "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", - "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", - "file-content-store", "hostname-verification", "response-splitting", "information-leak", - "xslt-injection", "template-injection", "fragment-injection", "command-injection", - "unsafe-deserialization", "xxe", "database-store", "format-string", - // .matches("credentials-%"), .matches("regex-use%")" - // shared MOST languages - "code-injection", // .matches("encryption-%"), - // Java only - "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", - "bean-validation", "intent-redirection", "pending-intents", - // JS only - "mongodb.sink", - // Swift only - "preferences-store", "transmission", "predicate-injection", "webview-fetch", - "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + // shared + "code-injection", "command-injection", "file-content-store", "html-injection", + "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", + "sql-injection", "url-redirection", + // Java-only currently, but may be shared in the future + "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", + "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", + "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", + "template-injection", "xpath-injection", "xslt-injection", + // JavaScript-only currently, but may be shared in the future + "mongodb.sink", "nosql-injection", "unsafe-deserialization", + // Swift-only currently, but may be shared in the future + "database-store", "format-string", "hash-iteration-count", "predicate-injection", + "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" ] + or + this.matches([ + // shared + "encryption-%", + // Java-only currently, but may be shared in the future + "regex-use%", + // JavaScript-only currently, but may be shared in the future + "credentials-%", + // Swift-only currently, but may be shared in the future + "%string-%length", "weak-hash-input-%" + ]) } } /** A valid models-as-data source kind. */ class ValidSourceKind extends string { + bindingset[this] ValidSourceKind() { this = [ - // shared ALL languages - "remote", "local" + // shared + "local", "remote", + // Java + "android-external-storage-dir", "contentprovider", + // C# + "file", "file-write", + // JavaScript + "database-access-result" ] + or + // Swift + this.matches("%string-%length") } } @@ -47,8 +66,10 @@ class ValidSummaryKind extends string { ValidSummaryKind() { this = [ - // shared ALL languages - "taint", "value" + // shared + "taint", "value", + // JavaScript + "type" ] } } @@ -58,8 +79,8 @@ class ValidNeutralKind extends string { ValidNeutralKind() { this = [ - // shared ALL languages - "summary", "source", "sink" + // Java/C# currently + "sink", "source", "summary" ] } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll index 8178dcf13d3..5b0105ad554 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll @@ -7,38 +7,57 @@ /** A valid models-as-data sink kind. */ class ValidSinkKind extends string { + bindingset[this] ValidSinkKind() { this = [ - // shared ALL languages - "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", - "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", - "file-content-store", "hostname-verification", "response-splitting", "information-leak", - "xslt-injection", "template-injection", "fragment-injection", "command-injection", - "unsafe-deserialization", "xxe", "database-store", "format-string", - // .matches("credentials-%"), .matches("regex-use%")" - // shared MOST languages - "code-injection", // .matches("encryption-%"), - // Java only - "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", - "bean-validation", "intent-redirection", "pending-intents", - // JS only - "mongodb.sink", - // Swift only - "preferences-store", "transmission", "predicate-injection", "webview-fetch", - "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + // shared + "code-injection", "command-injection", "file-content-store", "html-injection", + "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", + "sql-injection", "url-redirection", + // Java-only currently, but may be shared in the future + "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", + "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", + "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", + "template-injection", "xpath-injection", "xslt-injection", + // JavaScript-only currently, but may be shared in the future + "mongodb.sink", "nosql-injection", "unsafe-deserialization", + // Swift-only currently, but may be shared in the future + "database-store", "format-string", "hash-iteration-count", "predicate-injection", + "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" ] + or + this.matches([ + // shared + "encryption-%", + // Java-only currently, but may be shared in the future + "regex-use%", + // JavaScript-only currently, but may be shared in the future + "credentials-%", + // Swift-only currently, but may be shared in the future + "%string-%length", "weak-hash-input-%" + ]) } } /** A valid models-as-data source kind. */ class ValidSourceKind extends string { + bindingset[this] ValidSourceKind() { this = [ - // shared ALL languages - "remote", "local" + // shared + "local", "remote", + // Java + "android-external-storage-dir", "contentprovider", + // C# + "file", "file-write", + // JavaScript + "database-access-result" ] + or + // Swift + this.matches("%string-%length") } } @@ -47,8 +66,10 @@ class ValidSummaryKind extends string { ValidSummaryKind() { this = [ - // shared ALL languages - "taint", "value" + // shared + "taint", "value", + // JavaScript + "type" ] } } @@ -58,8 +79,8 @@ class ValidNeutralKind extends string { ValidNeutralKind() { this = [ - // shared ALL languages - "summary", "source", "sink" + // Java/C# currently + "sink", "source", "summary" ] } } diff --git a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll index 8178dcf13d3..5b0105ad554 100644 --- a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll +++ b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll @@ -7,38 +7,57 @@ /** A valid models-as-data sink kind. */ class ValidSinkKind extends string { + bindingset[this] ValidSinkKind() { this = [ - // shared ALL languages - "request-forgery", "ldap-injection", "sql-injection", "nosql-injection", "log-injection", - "xpath-injection", "html-injection", "js-injection", "url-redirection", "path-injection", - "file-content-store", "hostname-verification", "response-splitting", "information-leak", - "xslt-injection", "template-injection", "fragment-injection", "command-injection", - "unsafe-deserialization", "xxe", "database-store", "format-string", - // .matches("credentials-%"), .matches("regex-use%")" - // shared MOST languages - "code-injection", // .matches("encryption-%"), - // Java only - "jndi-injection", "mvel-injection", "groovy-injection", "ognl-injection", "jexl-injection", - "bean-validation", "intent-redirection", "pending-intents", - // JS only - "mongodb.sink", - // Swift only - "preferences-store", "transmission", "predicate-injection", "webview-fetch", - "tls-protocol-version", "hash-iteration-count" // .matches("%string-%length"), .matches("weak-hash-input-") + // shared + "code-injection", "command-injection", "file-content-store", "html-injection", + "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", + "sql-injection", "url-redirection", + // Java-only currently, but may be shared in the future + "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", + "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", + "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", + "template-injection", "xpath-injection", "xslt-injection", + // JavaScript-only currently, but may be shared in the future + "mongodb.sink", "nosql-injection", "unsafe-deserialization", + // Swift-only currently, but may be shared in the future + "database-store", "format-string", "hash-iteration-count", "predicate-injection", + "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" ] + or + this.matches([ + // shared + "encryption-%", + // Java-only currently, but may be shared in the future + "regex-use%", + // JavaScript-only currently, but may be shared in the future + "credentials-%", + // Swift-only currently, but may be shared in the future + "%string-%length", "weak-hash-input-%" + ]) } } /** A valid models-as-data source kind. */ class ValidSourceKind extends string { + bindingset[this] ValidSourceKind() { this = [ - // shared ALL languages - "remote", "local" + // shared + "local", "remote", + // Java + "android-external-storage-dir", "contentprovider", + // C# + "file", "file-write", + // JavaScript + "database-access-result" ] + or + // Swift + this.matches("%string-%length") } } @@ -47,8 +66,10 @@ class ValidSummaryKind extends string { ValidSummaryKind() { this = [ - // shared ALL languages - "taint", "value" + // shared + "taint", "value", + // JavaScript + "type" ] } } @@ -58,8 +79,8 @@ class ValidNeutralKind extends string { ValidNeutralKind() { this = [ - // shared ALL languages - "summary", "source", "sink" + // Java/C# currently + "sink", "source", "summary" ] } } From 9f42ae3f29309b060eaa71834a7a9b5755517be4 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Fri, 2 Jun 2023 16:52:20 -0400 Subject: [PATCH 035/364] Shared: remove cpp note --- config/identical-files.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/identical-files.json b/config/identical-files.json index cdda39b041a..800ae570bb8 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -599,7 +599,7 @@ "python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll", "java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll" ], - "SharedModelValidation Java/C#/Go/JS/Python/Ruby/Swift (C++ is problematic for now)": [ + "SharedModelValidation Java/C#/Go/JS/Python/Ruby/Swift": [ "java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll", "go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll", From 615f2a573b8165d79b00493a8d64fb9d65375dae Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Fri, 2 Jun 2023 16:57:24 -0400 Subject: [PATCH 036/364] Java/C#/Go/Swift: remove commented-out code --- .../semmle/code/csharp/dataflow/ExternalFlow.qll | 6 ------ go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 1 - .../lib/semmle/code/java/dataflow/ExternalFlow.qll | 13 ------------- swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll | 1 - 4 files changed, 21 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 902d6f246c9..32c143c6636 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -208,27 +208,21 @@ module ModelValidation { private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSummaryKind and - //not kind = ["taint", "value"] and result = "Invalid kind \"" + kind + "\" in summary model." ) or exists(string kind | sinkModel(_, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSinkKind and - // not kind = - // ["code-injection", "sql-injection", "js-injection", "html-injection", "file-content-store"] and - not kind.matches("encryption-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) or exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSourceKind and - //not kind = ["local", "remote", "file", "file-write"] and result = "Invalid kind \"" + kind + "\" in source model." ) or exists(string kind | neutralModel(_, _, _, _, kind, _) | not kind instanceof ValidNeutralKind and - //not kind = ["summary", "source", "sink"] and result = "Invalid kind \"" + kind + "\" in neutral model." ) } diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 05818ab68c7..9b12d3a2b38 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -192,7 +192,6 @@ module ModelValidation { private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSummaryKind and - //not kind = ["taint", "value"] and result = "Invalid kind \"" + kind + "\" in summary model." ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index b3a128fb4e1..3004910dc3f 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -313,22 +313,11 @@ module ModelValidation { private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSummaryKind and - //not kind = ["taint", "value"] and result = "Invalid kind \"" + kind + "\" in summary model." ) or exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSinkKind and - // not kind = - // [ - // "request-forgery", "jndi-injection", "ldap-injection", "sql-injection", "log-injection", - // "mvel-injection", "xpath-injection", "groovy-injection", "html-injection", "js-injection", - // "ognl-injection", "intent-redirection", "pending-intents", "url-redirection", - // "path-injection", "file-content-store", "hostname-verification", "response-splitting", - // "information-leak", "xslt-injection", "jexl-injection", "bean-validation", - // "template-injection", "fragment-injection", "command-injection" - // ] and - not kind.matches("regex-use%") and not kind.matches("qltest%") and msg = "Invalid kind \"" + kind + "\" in sink model." and // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. @@ -339,14 +328,12 @@ module ModelValidation { or exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSourceKind and - // not kind = ["remote", "contentprovider", "android-widget", "android-external-storage-dir"] and not kind.matches("qltest%") and result = "Invalid kind \"" + kind + "\" in source model." ) or exists(string kind | neutralModel(_, _, _, _, kind, _) | not kind instanceof ValidNeutralKind and - //not kind = ["summary", "source", "sink"] and result = "Invalid kind \"" + kind + "\" in neutral model." ) } diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index 0adc9be7373..62e785ebf31 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -268,7 +268,6 @@ module CsvValidation { exists(string row, string kind | summaryModel(row) | kind = row.splitAt(";", 8) and not kind instanceof ValidSummaryKind and - //not kind = ["taint", "value"] and result = "Invalid kind \"" + kind + "\" in summary model." ) } From 254e4479234e6af9e9dbf0b27f1cd3ce4192d679 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Fri, 2 Jun 2023 17:00:39 -0400 Subject: [PATCH 037/364] JS/Python/Ruby: update getInvalidModelKind --- .../javascript/frameworks/data/internal/ApiGraphModels.qll | 2 -- .../semmle/python/frameworks/data/internal/ApiGraphModels.qll | 2 -- .../lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll | 2 -- 3 files changed, 6 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index 4799f75937e..dd46283be4b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -663,14 +663,12 @@ module ModelOutput { or exists(string kind | sinkModel(_, _, kind) | not kind instanceof ValidSinkKind and - not kind.matches("credentials-%") and not kind.matches("test-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) or exists(string kind | sourceModel(_, _, kind) | not kind instanceof ValidSourceKind and - not kind.matches("qltest%") and result = "Invalid kind \"" + kind + "\" in source model." ) } diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index 4799f75937e..dd46283be4b 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -663,14 +663,12 @@ module ModelOutput { or exists(string kind | sinkModel(_, _, kind) | not kind instanceof ValidSinkKind and - not kind.matches("credentials-%") and not kind.matches("test-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) or exists(string kind | sourceModel(_, _, kind) | not kind instanceof ValidSourceKind and - not kind.matches("qltest%") and result = "Invalid kind \"" + kind + "\" in source model." ) } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index 4799f75937e..dd46283be4b 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -663,14 +663,12 @@ module ModelOutput { or exists(string kind | sinkModel(_, _, kind) | not kind instanceof ValidSinkKind and - not kind.matches("credentials-%") and not kind.matches("test-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) or exists(string kind | sourceModel(_, _, kind) | not kind instanceof ValidSourceKind and - not kind.matches("qltest%") and result = "Invalid kind \"" + kind + "\" in source model." ) } From 76508d17c6487eed6bbbd5674e7a3255e62f9af3 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Fri, 2 Jun 2023 18:04:06 -0400 Subject: [PATCH 038/364] Go/Swift: validate source/sink kinds --- go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 10 ++++++++++ swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 9b12d3a2b38..ca45d36320e 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -194,6 +194,16 @@ module ModelValidation { not kind instanceof ValidSummaryKind and result = "Invalid kind \"" + kind + "\" in summary model." ) + or + exists(string kind | sinkModel(_, _, _, _, _, _, _, kind, _) | + not kind instanceof ValidSinkKind and + result = "Invalid kind \"" + kind + "\" in sink model." + ) + or + exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | + not kind instanceof ValidSourceKind and + result = "Invalid kind \"" + kind + "\" in source model." + ) } private string getInvalidModelSignature() { diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index 62e785ebf31..46085f27568 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -270,6 +270,16 @@ module CsvValidation { not kind instanceof ValidSummaryKind and result = "Invalid kind \"" + kind + "\" in summary model." ) + or + exists(string kind | sinkModel(_, _, _, _, _, _, _, kind, _) | + not kind instanceof ValidSinkKind and + result = "Invalid kind \"" + kind + "\" in sink model." + ) + or + exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | + not kind instanceof ValidSourceKind and + result = "Invalid kind \"" + kind + "\" in source model." + ) } private string getInvalidModelSubtype() { From 7b629f5d63deb67fc8ec10cc7fdf652a4de3bb0e Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 5 Jun 2023 08:23:31 -0400 Subject: [PATCH 039/364] Shared: include 'qltest%' and 'test-%' --- .../code/csharp/dataflow/SharedModelValidation.qll | 12 ++++++++---- .../lib/semmle/go/dataflow/SharedModelValidation.qll | 12 ++++++++---- .../lib/semmle/code/java/dataflow/ExternalFlow.qll | 2 -- .../code/java/dataflow/SharedModelValidation.qll | 12 ++++++++---- .../frameworks/data/internal/ApiGraphModels.qll | 1 - .../data/internal/SharedModelValidation.qll | 12 ++++++++---- .../frameworks/data/internal/ApiGraphModels.qll | 1 - .../data/internal/SharedModelValidation.qll | 12 ++++++++---- .../ruby/frameworks/data/internal/ApiGraphModels.qll | 1 - .../data/internal/SharedModelValidation.qll | 12 ++++++++---- .../codeql/swift/dataflow/SharedModelValidation.qll | 12 ++++++++---- 11 files changed, 56 insertions(+), 33 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll index 5b0105ad554..f38e90257d1 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll @@ -29,7 +29,7 @@ class ValidSinkKind extends string { or this.matches([ // shared - "encryption-%", + "encryption-%", "qltest%", "test-%", // Java-only currently, but may be shared in the future "regex-use%", // JavaScript-only currently, but may be shared in the future @@ -53,11 +53,15 @@ class ValidSourceKind extends string { // C# "file", "file-write", // JavaScript - "database-access-result" + "database-access-result", "remote-flow" ] or - // Swift - this.matches("%string-%length") + this.matches([ + // shared + "qltest%", "test-%", + // Swift + "%string-%length" + ]) } } diff --git a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll index 5b0105ad554..f38e90257d1 100644 --- a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll +++ b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll @@ -29,7 +29,7 @@ class ValidSinkKind extends string { or this.matches([ // shared - "encryption-%", + "encryption-%", "qltest%", "test-%", // Java-only currently, but may be shared in the future "regex-use%", // JavaScript-only currently, but may be shared in the future @@ -53,11 +53,15 @@ class ValidSourceKind extends string { // C# "file", "file-write", // JavaScript - "database-access-result" + "database-access-result", "remote-flow" ] or - // Swift - this.matches("%string-%length") + this.matches([ + // shared + "qltest%", "test-%", + // Swift + "%string-%length" + ]) } } diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 3004910dc3f..2c63d9d37a0 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -318,7 +318,6 @@ module ModelValidation { or exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSinkKind and - not kind.matches("qltest%") and msg = "Invalid kind \"" + kind + "\" in sink model." and // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. if kind instanceof OutdatedSinkKind @@ -328,7 +327,6 @@ module ModelValidation { or exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSourceKind and - not kind.matches("qltest%") and result = "Invalid kind \"" + kind + "\" in source model." ) or diff --git a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll index 5b0105ad554..f38e90257d1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll +++ b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll @@ -29,7 +29,7 @@ class ValidSinkKind extends string { or this.matches([ // shared - "encryption-%", + "encryption-%", "qltest%", "test-%", // Java-only currently, but may be shared in the future "regex-use%", // JavaScript-only currently, but may be shared in the future @@ -53,11 +53,15 @@ class ValidSourceKind extends string { // C# "file", "file-write", // JavaScript - "database-access-result" + "database-access-result", "remote-flow" ] or - // Swift - this.matches("%string-%length") + this.matches([ + // shared + "qltest%", "test-%", + // Swift + "%string-%length" + ]) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index dd46283be4b..b0dd297b6c6 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -663,7 +663,6 @@ module ModelOutput { or exists(string kind | sinkModel(_, _, kind) | not kind instanceof ValidSinkKind and - not kind.matches("test-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) or diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll index 5b0105ad554..f38e90257d1 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll @@ -29,7 +29,7 @@ class ValidSinkKind extends string { or this.matches([ // shared - "encryption-%", + "encryption-%", "qltest%", "test-%", // Java-only currently, but may be shared in the future "regex-use%", // JavaScript-only currently, but may be shared in the future @@ -53,11 +53,15 @@ class ValidSourceKind extends string { // C# "file", "file-write", // JavaScript - "database-access-result" + "database-access-result", "remote-flow" ] or - // Swift - this.matches("%string-%length") + this.matches([ + // shared + "qltest%", "test-%", + // Swift + "%string-%length" + ]) } } diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index dd46283be4b..b0dd297b6c6 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -663,7 +663,6 @@ module ModelOutput { or exists(string kind | sinkModel(_, _, kind) | not kind instanceof ValidSinkKind and - not kind.matches("test-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) or diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll index 5b0105ad554..f38e90257d1 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll @@ -29,7 +29,7 @@ class ValidSinkKind extends string { or this.matches([ // shared - "encryption-%", + "encryption-%", "qltest%", "test-%", // Java-only currently, but may be shared in the future "regex-use%", // JavaScript-only currently, but may be shared in the future @@ -53,11 +53,15 @@ class ValidSourceKind extends string { // C# "file", "file-write", // JavaScript - "database-access-result" + "database-access-result", "remote-flow" ] or - // Swift - this.matches("%string-%length") + this.matches([ + // shared + "qltest%", "test-%", + // Swift + "%string-%length" + ]) } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index dd46283be4b..b0dd297b6c6 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -663,7 +663,6 @@ module ModelOutput { or exists(string kind | sinkModel(_, _, kind) | not kind instanceof ValidSinkKind and - not kind.matches("test-%") and result = "Invalid kind \"" + kind + "\" in sink model." ) or diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll index 5b0105ad554..f38e90257d1 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll @@ -29,7 +29,7 @@ class ValidSinkKind extends string { or this.matches([ // shared - "encryption-%", + "encryption-%", "qltest%", "test-%", // Java-only currently, but may be shared in the future "regex-use%", // JavaScript-only currently, but may be shared in the future @@ -53,11 +53,15 @@ class ValidSourceKind extends string { // C# "file", "file-write", // JavaScript - "database-access-result" + "database-access-result", "remote-flow" ] or - // Swift - this.matches("%string-%length") + this.matches([ + // shared + "qltest%", "test-%", + // Swift + "%string-%length" + ]) } } diff --git a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll index 5b0105ad554..f38e90257d1 100644 --- a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll +++ b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll @@ -29,7 +29,7 @@ class ValidSinkKind extends string { or this.matches([ // shared - "encryption-%", + "encryption-%", "qltest%", "test-%", // Java-only currently, but may be shared in the future "regex-use%", // JavaScript-only currently, but may be shared in the future @@ -53,11 +53,15 @@ class ValidSourceKind extends string { // C# "file", "file-write", // JavaScript - "database-access-result" + "database-access-result", "remote-flow" ] or - // Swift - this.matches("%string-%length") + this.matches([ + // shared + "qltest%", "test-%", + // Swift + "%string-%length" + ]) } } From 76f5dca861d71f1e7cd43e25c109bc09a8ca89a8 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 5 Jun 2023 08:51:55 -0400 Subject: [PATCH 040/364] Shared: move 'OutdatedSinkKind' to shared file and add outdated JS and C# sink kinds --- .../csharp/dataflow/SharedModelValidation.qll | 46 +++++++++++++++++++ .../go/dataflow/SharedModelValidation.qll | 46 +++++++++++++++++++ .../code/java/dataflow/ExternalFlow.qll | 44 ------------------ .../java/dataflow/SharedModelValidation.qll | 46 +++++++++++++++++++ .../data/internal/SharedModelValidation.qll | 46 +++++++++++++++++++ .../data/internal/SharedModelValidation.qll | 46 +++++++++++++++++++ .../data/internal/SharedModelValidation.qll | 46 +++++++++++++++++++ .../swift/dataflow/SharedModelValidation.qll | 46 +++++++++++++++++++ 8 files changed, 322 insertions(+), 44 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll index f38e90257d1..e68b8241897 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll @@ -40,6 +40,52 @@ class ValidSinkKind extends string { } } +class OutdatedSinkKind extends string { + OutdatedSinkKind() { + this = + [ + "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", + "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", + "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", + "code", "html", "remote" + ] + } + + private string replacementKind() { + this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and + result = this + "-injection" + or + this = "url-redirect" and result = "url-redirection" + or + this = "ssti" and result = "template-injection" + or + this = "logging" and result = "log-injection" + or + this = "pending-intent-sent" and result = "pending-intents" + or + this = "intent-start" and result = "intent-redirection" + or + this = "set-hostname-verifier" and result = "hostname-verification" + or + this = "header-splitting" and result = "response-splitting" + or + this = "xss" and result = "html-injection\" or \"js-injection" + or + this = ["write-file", "remote"] and result = "file-content-store" + or + this = ["create-file", "read-file"] and result = "path-injection" + or + this = ["open-url", "jdbc-url"] and result = "request-forgery" + or + this = "command-line-injection" and result = "command-injection" + } + + string outdatedMessage() { + result = + "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." + } +} + /** A valid models-as-data source kind. */ class ValidSourceKind extends string { bindingset[this] diff --git a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll index f38e90257d1..e68b8241897 100644 --- a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll +++ b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll @@ -40,6 +40,52 @@ class ValidSinkKind extends string { } } +class OutdatedSinkKind extends string { + OutdatedSinkKind() { + this = + [ + "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", + "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", + "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", + "code", "html", "remote" + ] + } + + private string replacementKind() { + this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and + result = this + "-injection" + or + this = "url-redirect" and result = "url-redirection" + or + this = "ssti" and result = "template-injection" + or + this = "logging" and result = "log-injection" + or + this = "pending-intent-sent" and result = "pending-intents" + or + this = "intent-start" and result = "intent-redirection" + or + this = "set-hostname-verifier" and result = "hostname-verification" + or + this = "header-splitting" and result = "response-splitting" + or + this = "xss" and result = "html-injection\" or \"js-injection" + or + this = ["write-file", "remote"] and result = "file-content-store" + or + this = ["create-file", "read-file"] and result = "path-injection" + or + this = ["open-url", "jdbc-url"] and result = "request-forgery" + or + this = "command-line-injection" and result = "command-injection" + } + + string outdatedMessage() { + result = + "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." + } +} + /** A valid models-as-data source kind. */ class ValidSourceKind extends string { bindingset[this] diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 2c63d9d37a0..77bdf56195e 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -266,50 +266,6 @@ module ModelValidation { ) } - private class OutdatedSinkKind extends string { - OutdatedSinkKind() { - this = - [ - "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", - "ldap", "pending-intent-sent", "intent-start", "set-hostname-verifier", - "header-splitting", "xss", "write-file", "create-file", "read-file", "open-url", - "jdbc-url" - ] - } - - private string replacementKind() { - this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap"] and - result = this + "-injection" - or - this = "url-redirect" and result = "url-redirection" - or - this = "ssti" and result = "template-injection" - or - this = "logging" and result = "log-injection" - or - this = "pending-intent-sent" and result = "pending-intents" - or - this = "intent-start" and result = "intent-redirection" - or - this = "set-hostname-verifier" and result = "hostname-verification" - or - this = "header-splitting" and result = "response-splitting" - or - this = "xss" and result = "html-injection\" or \"js-injection" - or - this = "write-file" and result = "file-content-store" - or - this = ["create-file", "read-file"] and result = "path-injection" - or - this = ["open-url", "jdbc-url"] and result = "request-forgery" - } - - string outdatedMessage() { - result = - "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." - } - } - private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSummaryKind and diff --git a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll index f38e90257d1..e68b8241897 100644 --- a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll +++ b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll @@ -40,6 +40,52 @@ class ValidSinkKind extends string { } } +class OutdatedSinkKind extends string { + OutdatedSinkKind() { + this = + [ + "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", + "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", + "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", + "code", "html", "remote" + ] + } + + private string replacementKind() { + this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and + result = this + "-injection" + or + this = "url-redirect" and result = "url-redirection" + or + this = "ssti" and result = "template-injection" + or + this = "logging" and result = "log-injection" + or + this = "pending-intent-sent" and result = "pending-intents" + or + this = "intent-start" and result = "intent-redirection" + or + this = "set-hostname-verifier" and result = "hostname-verification" + or + this = "header-splitting" and result = "response-splitting" + or + this = "xss" and result = "html-injection\" or \"js-injection" + or + this = ["write-file", "remote"] and result = "file-content-store" + or + this = ["create-file", "read-file"] and result = "path-injection" + or + this = ["open-url", "jdbc-url"] and result = "request-forgery" + or + this = "command-line-injection" and result = "command-injection" + } + + string outdatedMessage() { + result = + "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." + } +} + /** A valid models-as-data source kind. */ class ValidSourceKind extends string { bindingset[this] diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll index f38e90257d1..e68b8241897 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll @@ -40,6 +40,52 @@ class ValidSinkKind extends string { } } +class OutdatedSinkKind extends string { + OutdatedSinkKind() { + this = + [ + "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", + "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", + "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", + "code", "html", "remote" + ] + } + + private string replacementKind() { + this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and + result = this + "-injection" + or + this = "url-redirect" and result = "url-redirection" + or + this = "ssti" and result = "template-injection" + or + this = "logging" and result = "log-injection" + or + this = "pending-intent-sent" and result = "pending-intents" + or + this = "intent-start" and result = "intent-redirection" + or + this = "set-hostname-verifier" and result = "hostname-verification" + or + this = "header-splitting" and result = "response-splitting" + or + this = "xss" and result = "html-injection\" or \"js-injection" + or + this = ["write-file", "remote"] and result = "file-content-store" + or + this = ["create-file", "read-file"] and result = "path-injection" + or + this = ["open-url", "jdbc-url"] and result = "request-forgery" + or + this = "command-line-injection" and result = "command-injection" + } + + string outdatedMessage() { + result = + "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." + } +} + /** A valid models-as-data source kind. */ class ValidSourceKind extends string { bindingset[this] diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll index f38e90257d1..e68b8241897 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll @@ -40,6 +40,52 @@ class ValidSinkKind extends string { } } +class OutdatedSinkKind extends string { + OutdatedSinkKind() { + this = + [ + "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", + "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", + "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", + "code", "html", "remote" + ] + } + + private string replacementKind() { + this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and + result = this + "-injection" + or + this = "url-redirect" and result = "url-redirection" + or + this = "ssti" and result = "template-injection" + or + this = "logging" and result = "log-injection" + or + this = "pending-intent-sent" and result = "pending-intents" + or + this = "intent-start" and result = "intent-redirection" + or + this = "set-hostname-verifier" and result = "hostname-verification" + or + this = "header-splitting" and result = "response-splitting" + or + this = "xss" and result = "html-injection\" or \"js-injection" + or + this = ["write-file", "remote"] and result = "file-content-store" + or + this = ["create-file", "read-file"] and result = "path-injection" + or + this = ["open-url", "jdbc-url"] and result = "request-forgery" + or + this = "command-line-injection" and result = "command-injection" + } + + string outdatedMessage() { + result = + "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." + } +} + /** A valid models-as-data source kind. */ class ValidSourceKind extends string { bindingset[this] diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll index f38e90257d1..e68b8241897 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll @@ -40,6 +40,52 @@ class ValidSinkKind extends string { } } +class OutdatedSinkKind extends string { + OutdatedSinkKind() { + this = + [ + "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", + "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", + "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", + "code", "html", "remote" + ] + } + + private string replacementKind() { + this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and + result = this + "-injection" + or + this = "url-redirect" and result = "url-redirection" + or + this = "ssti" and result = "template-injection" + or + this = "logging" and result = "log-injection" + or + this = "pending-intent-sent" and result = "pending-intents" + or + this = "intent-start" and result = "intent-redirection" + or + this = "set-hostname-verifier" and result = "hostname-verification" + or + this = "header-splitting" and result = "response-splitting" + or + this = "xss" and result = "html-injection\" or \"js-injection" + or + this = ["write-file", "remote"] and result = "file-content-store" + or + this = ["create-file", "read-file"] and result = "path-injection" + or + this = ["open-url", "jdbc-url"] and result = "request-forgery" + or + this = "command-line-injection" and result = "command-injection" + } + + string outdatedMessage() { + result = + "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." + } +} + /** A valid models-as-data source kind. */ class ValidSourceKind extends string { bindingset[this] diff --git a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll index f38e90257d1..e68b8241897 100644 --- a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll +++ b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll @@ -40,6 +40,52 @@ class ValidSinkKind extends string { } } +class OutdatedSinkKind extends string { + OutdatedSinkKind() { + this = + [ + "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", + "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", + "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", + "code", "html", "remote" + ] + } + + private string replacementKind() { + this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and + result = this + "-injection" + or + this = "url-redirect" and result = "url-redirection" + or + this = "ssti" and result = "template-injection" + or + this = "logging" and result = "log-injection" + or + this = "pending-intent-sent" and result = "pending-intents" + or + this = "intent-start" and result = "intent-redirection" + or + this = "set-hostname-verifier" and result = "hostname-verification" + or + this = "header-splitting" and result = "response-splitting" + or + this = "xss" and result = "html-injection\" or \"js-injection" + or + this = ["write-file", "remote"] and result = "file-content-store" + or + this = ["create-file", "read-file"] and result = "path-injection" + or + this = ["open-url", "jdbc-url"] and result = "request-forgery" + or + this = "command-line-injection" and result = "command-injection" + } + + string outdatedMessage() { + result = + "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." + } +} + /** A valid models-as-data source kind. */ class ValidSourceKind extends string { bindingset[this] From 62ac0dc47108c0424d01621b8876e2792cf092c0 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 5 Jun 2023 09:16:42 -0400 Subject: [PATCH 041/364] Shared: add outdated sink kind msg to 'getInvalidModelKind' for all languages --- .../ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll | 8 ++++++-- go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 8 ++++++-- .../frameworks/data/internal/ApiGraphModels.qll | 8 ++++++-- .../python/frameworks/data/internal/ApiGraphModels.qll | 8 ++++++-- .../ruby/frameworks/data/internal/ApiGraphModels.qll | 8 ++++++-- swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll | 8 ++++++-- 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 32c143c6636..5592dbe86c0 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -216,9 +216,13 @@ module ModelValidation { result = "Invalid kind \"" + kind + "\" in sink model." ) or - exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | + exists(string kind, string msg | sourceModel(_, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSourceKind and - result = "Invalid kind \"" + kind + "\" in source model." + msg = "Invalid kind \"" + kind + "\" in sink model." and + // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. + if kind instanceof OutdatedSinkKind + then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() + else result = msg ) or exists(string kind | neutralModel(_, _, _, _, kind, _) | diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index ca45d36320e..214e9d93285 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -195,9 +195,13 @@ module ModelValidation { result = "Invalid kind \"" + kind + "\" in summary model." ) or - exists(string kind | sinkModel(_, _, _, _, _, _, _, kind, _) | + exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSinkKind and - result = "Invalid kind \"" + kind + "\" in sink model." + msg = "Invalid kind \"" + kind + "\" in sink model." and + // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. + if kind instanceof OutdatedSinkKind + then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() + else result = msg ) or exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index b0dd297b6c6..baf732c7d0c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -661,9 +661,13 @@ module ModelOutput { result = "Invalid kind \"" + kind + "\" in summary model." ) or - exists(string kind | sinkModel(_, _, kind) | + exists(string kind, string msg | sinkModel(_, _, kind) | not kind instanceof ValidSinkKind and - result = "Invalid kind \"" + kind + "\" in sink model." + msg = "Invalid kind \"" + kind + "\" in sink model." and + // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. + if kind instanceof OutdatedSinkKind + then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() + else result = msg ) or exists(string kind | sourceModel(_, _, kind) | diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index b0dd297b6c6..baf732c7d0c 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -661,9 +661,13 @@ module ModelOutput { result = "Invalid kind \"" + kind + "\" in summary model." ) or - exists(string kind | sinkModel(_, _, kind) | + exists(string kind, string msg | sinkModel(_, _, kind) | not kind instanceof ValidSinkKind and - result = "Invalid kind \"" + kind + "\" in sink model." + msg = "Invalid kind \"" + kind + "\" in sink model." and + // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. + if kind instanceof OutdatedSinkKind + then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() + else result = msg ) or exists(string kind | sourceModel(_, _, kind) | diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index b0dd297b6c6..baf732c7d0c 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -661,9 +661,13 @@ module ModelOutput { result = "Invalid kind \"" + kind + "\" in summary model." ) or - exists(string kind | sinkModel(_, _, kind) | + exists(string kind, string msg | sinkModel(_, _, kind) | not kind instanceof ValidSinkKind and - result = "Invalid kind \"" + kind + "\" in sink model." + msg = "Invalid kind \"" + kind + "\" in sink model." and + // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. + if kind instanceof OutdatedSinkKind + then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() + else result = msg ) or exists(string kind | sourceModel(_, _, kind) | diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index 46085f27568..77dc65cf746 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -271,9 +271,13 @@ module CsvValidation { result = "Invalid kind \"" + kind + "\" in summary model." ) or - exists(string kind | sinkModel(_, _, _, _, _, _, _, kind, _) | + exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSinkKind and - result = "Invalid kind \"" + kind + "\" in sink model." + msg = "Invalid kind \"" + kind + "\" in sink model." and + // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. + if kind instanceof OutdatedSinkKind + then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() + else result = msg ) or exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | From 3f1dc8e5c79ea14f84aba30c0cfda1660a4ed5ce Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 5 Jun 2023 09:21:32 -0400 Subject: [PATCH 042/364] Shared: add outdated Swift sink kinds --- .../semmle/code/csharp/dataflow/SharedModelValidation.qll | 6 +++++- go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll | 6 +++++- .../lib/semmle/code/java/dataflow/SharedModelValidation.qll | 6 +++++- .../frameworks/data/internal/SharedModelValidation.qll | 6 +++++- .../frameworks/data/internal/SharedModelValidation.qll | 6 +++++- .../ruby/frameworks/data/internal/SharedModelValidation.qll | 6 +++++- .../ql/lib/codeql/swift/dataflow/SharedModelValidation.qll | 6 +++++- 7 files changed, 35 insertions(+), 7 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll index e68b8241897..40aad9caef7 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll @@ -47,7 +47,7 @@ class OutdatedSinkKind extends string { "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote" + "code", "html", "remote", "uncontrolled-format-string", "js-eval" ] } @@ -55,6 +55,8 @@ class OutdatedSinkKind extends string { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" or + this = "js-eval" and result = "code-injection" + or this = "url-redirect" and result = "url-redirection" or this = "ssti" and result = "template-injection" @@ -78,6 +80,8 @@ class OutdatedSinkKind extends string { this = ["open-url", "jdbc-url"] and result = "request-forgery" or this = "command-line-injection" and result = "command-injection" + or + this = "uncontrolled-format-string" and result = "format-string" } string outdatedMessage() { diff --git a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll index e68b8241897..40aad9caef7 100644 --- a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll +++ b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll @@ -47,7 +47,7 @@ class OutdatedSinkKind extends string { "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote" + "code", "html", "remote", "uncontrolled-format-string", "js-eval" ] } @@ -55,6 +55,8 @@ class OutdatedSinkKind extends string { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" or + this = "js-eval" and result = "code-injection" + or this = "url-redirect" and result = "url-redirection" or this = "ssti" and result = "template-injection" @@ -78,6 +80,8 @@ class OutdatedSinkKind extends string { this = ["open-url", "jdbc-url"] and result = "request-forgery" or this = "command-line-injection" and result = "command-injection" + or + this = "uncontrolled-format-string" and result = "format-string" } string outdatedMessage() { diff --git a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll index e68b8241897..40aad9caef7 100644 --- a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll +++ b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll @@ -47,7 +47,7 @@ class OutdatedSinkKind extends string { "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote" + "code", "html", "remote", "uncontrolled-format-string", "js-eval" ] } @@ -55,6 +55,8 @@ class OutdatedSinkKind extends string { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" or + this = "js-eval" and result = "code-injection" + or this = "url-redirect" and result = "url-redirection" or this = "ssti" and result = "template-injection" @@ -78,6 +80,8 @@ class OutdatedSinkKind extends string { this = ["open-url", "jdbc-url"] and result = "request-forgery" or this = "command-line-injection" and result = "command-injection" + or + this = "uncontrolled-format-string" and result = "format-string" } string outdatedMessage() { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll index e68b8241897..40aad9caef7 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll @@ -47,7 +47,7 @@ class OutdatedSinkKind extends string { "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote" + "code", "html", "remote", "uncontrolled-format-string", "js-eval" ] } @@ -55,6 +55,8 @@ class OutdatedSinkKind extends string { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" or + this = "js-eval" and result = "code-injection" + or this = "url-redirect" and result = "url-redirection" or this = "ssti" and result = "template-injection" @@ -78,6 +80,8 @@ class OutdatedSinkKind extends string { this = ["open-url", "jdbc-url"] and result = "request-forgery" or this = "command-line-injection" and result = "command-injection" + or + this = "uncontrolled-format-string" and result = "format-string" } string outdatedMessage() { diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll index e68b8241897..40aad9caef7 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll @@ -47,7 +47,7 @@ class OutdatedSinkKind extends string { "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote" + "code", "html", "remote", "uncontrolled-format-string", "js-eval" ] } @@ -55,6 +55,8 @@ class OutdatedSinkKind extends string { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" or + this = "js-eval" and result = "code-injection" + or this = "url-redirect" and result = "url-redirection" or this = "ssti" and result = "template-injection" @@ -78,6 +80,8 @@ class OutdatedSinkKind extends string { this = ["open-url", "jdbc-url"] and result = "request-forgery" or this = "command-line-injection" and result = "command-injection" + or + this = "uncontrolled-format-string" and result = "format-string" } string outdatedMessage() { diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll index e68b8241897..40aad9caef7 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll @@ -47,7 +47,7 @@ class OutdatedSinkKind extends string { "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote" + "code", "html", "remote", "uncontrolled-format-string", "js-eval" ] } @@ -55,6 +55,8 @@ class OutdatedSinkKind extends string { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" or + this = "js-eval" and result = "code-injection" + or this = "url-redirect" and result = "url-redirection" or this = "ssti" and result = "template-injection" @@ -78,6 +80,8 @@ class OutdatedSinkKind extends string { this = ["open-url", "jdbc-url"] and result = "request-forgery" or this = "command-line-injection" and result = "command-injection" + or + this = "uncontrolled-format-string" and result = "format-string" } string outdatedMessage() { diff --git a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll index e68b8241897..40aad9caef7 100644 --- a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll +++ b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll @@ -47,7 +47,7 @@ class OutdatedSinkKind extends string { "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote" + "code", "html", "remote", "uncontrolled-format-string", "js-eval" ] } @@ -55,6 +55,8 @@ class OutdatedSinkKind extends string { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" or + this = "js-eval" and result = "code-injection" + or this = "url-redirect" and result = "url-redirection" or this = "ssti" and result = "template-injection" @@ -78,6 +80,8 @@ class OutdatedSinkKind extends string { this = ["open-url", "jdbc-url"] and result = "request-forgery" or this = "command-line-injection" and result = "command-injection" + or + this = "uncontrolled-format-string" and result = "format-string" } string outdatedMessage() { From 9d5972acc2a3c84f158e4dd9ca99e9d75f180599 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 5 Jun 2023 12:16:08 -0400 Subject: [PATCH 043/364] Shared: update qldocs --- csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll | 1 + .../semmle/code/csharp/dataflow/SharedModelValidation.qll | 5 ++++- go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 1 + go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll | 5 ++++- java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll | 1 + .../lib/semmle/code/java/dataflow/SharedModelValidation.qll | 5 ++++- .../javascript/frameworks/data/internal/ApiGraphModels.qll | 1 + .../frameworks/data/internal/SharedModelValidation.qll | 5 ++++- .../python/frameworks/data/internal/ApiGraphModels.qll | 1 + .../frameworks/data/internal/SharedModelValidation.qll | 5 ++++- .../codeql/ruby/frameworks/data/internal/ApiGraphModels.qll | 1 + .../ruby/frameworks/data/internal/SharedModelValidation.qll | 5 ++++- swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll | 1 + swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll | 5 ++++- 14 files changed, 35 insertions(+), 7 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 5592dbe86c0..2093646a1f1 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -205,6 +205,7 @@ module ModelValidation { ) } + /** Gets an error message relating to an invalid kind in a model. */ private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSummaryKind and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll index 40aad9caef7..9d863671941 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes for validating kinds in models as data rows. + * Provides classes and predicates related to validating models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ @@ -40,6 +40,7 @@ class ValidSinkKind extends string { } } +/** An outdated models-as-data sink kind. */ class OutdatedSinkKind extends string { OutdatedSinkKind() { this = @@ -51,6 +52,7 @@ class OutdatedSinkKind extends string { ] } + /** Gets a replacement kind for an outdated sink kind. */ private string replacementKind() { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" @@ -84,6 +86,7 @@ class OutdatedSinkKind extends string { this = "uncontrolled-format-string" and result = "format-string" } + /** Gets an error message for an outdated sink kind. */ string outdatedMessage() { result = "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 214e9d93285..10146aae3b9 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -189,6 +189,7 @@ module ModelValidation { ) } + /** Gets an error message relating to an invalid kind in a model. */ private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSummaryKind and diff --git a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll index 40aad9caef7..9d863671941 100644 --- a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll +++ b/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes for validating kinds in models as data rows. + * Provides classes and predicates related to validating models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ @@ -40,6 +40,7 @@ class ValidSinkKind extends string { } } +/** An outdated models-as-data sink kind. */ class OutdatedSinkKind extends string { OutdatedSinkKind() { this = @@ -51,6 +52,7 @@ class OutdatedSinkKind extends string { ] } + /** Gets a replacement kind for an outdated sink kind. */ private string replacementKind() { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" @@ -84,6 +86,7 @@ class OutdatedSinkKind extends string { this = "uncontrolled-format-string" and result = "format-string" } + /** Gets an error message for an outdated sink kind. */ string outdatedMessage() { result = "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 77bdf56195e..1f6e64d9b76 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -266,6 +266,7 @@ module ModelValidation { ) } + /** Gets an error message relating to an invalid kind in a model. */ private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSummaryKind and diff --git a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll index 40aad9caef7..9d863671941 100644 --- a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll +++ b/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes for validating kinds in models as data rows. + * Provides classes and predicates related to validating models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ @@ -40,6 +40,7 @@ class ValidSinkKind extends string { } } +/** An outdated models-as-data sink kind. */ class OutdatedSinkKind extends string { OutdatedSinkKind() { this = @@ -51,6 +52,7 @@ class OutdatedSinkKind extends string { ] } + /** Gets a replacement kind for an outdated sink kind. */ private string replacementKind() { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" @@ -84,6 +86,7 @@ class OutdatedSinkKind extends string { this = "uncontrolled-format-string" and result = "format-string" } + /** Gets an error message for an outdated sink kind. */ string outdatedMessage() { result = "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index baf732c7d0c..fe4fa8c9c2d 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -655,6 +655,7 @@ module ModelOutput { import Specific::ModelOutputSpecific private import SharedModelValidation + /** Gets an error message relating to an invalid kind in a model. */ private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, kind) | not kind instanceof ValidSummaryKind and diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll index 40aad9caef7..9d863671941 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes for validating kinds in models as data rows. + * Provides classes and predicates related to validating models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ @@ -40,6 +40,7 @@ class ValidSinkKind extends string { } } +/** An outdated models-as-data sink kind. */ class OutdatedSinkKind extends string { OutdatedSinkKind() { this = @@ -51,6 +52,7 @@ class OutdatedSinkKind extends string { ] } + /** Gets a replacement kind for an outdated sink kind. */ private string replacementKind() { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" @@ -84,6 +86,7 @@ class OutdatedSinkKind extends string { this = "uncontrolled-format-string" and result = "format-string" } + /** Gets an error message for an outdated sink kind. */ string outdatedMessage() { result = "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index baf732c7d0c..fe4fa8c9c2d 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -655,6 +655,7 @@ module ModelOutput { import Specific::ModelOutputSpecific private import SharedModelValidation + /** Gets an error message relating to an invalid kind in a model. */ private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, kind) | not kind instanceof ValidSummaryKind and diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll index 40aad9caef7..9d863671941 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes for validating kinds in models as data rows. + * Provides classes and predicates related to validating models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ @@ -40,6 +40,7 @@ class ValidSinkKind extends string { } } +/** An outdated models-as-data sink kind. */ class OutdatedSinkKind extends string { OutdatedSinkKind() { this = @@ -51,6 +52,7 @@ class OutdatedSinkKind extends string { ] } + /** Gets a replacement kind for an outdated sink kind. */ private string replacementKind() { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" @@ -84,6 +86,7 @@ class OutdatedSinkKind extends string { this = "uncontrolled-format-string" and result = "format-string" } + /** Gets an error message for an outdated sink kind. */ string outdatedMessage() { result = "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index baf732c7d0c..fe4fa8c9c2d 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -655,6 +655,7 @@ module ModelOutput { import Specific::ModelOutputSpecific private import SharedModelValidation + /** Gets an error message relating to an invalid kind in a model. */ private string getInvalidModelKind() { exists(string kind | summaryModel(_, _, _, _, kind) | not kind instanceof ValidSummaryKind and diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll index 40aad9caef7..9d863671941 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes for validating kinds in models as data rows. + * Provides classes and predicates related to validating models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ @@ -40,6 +40,7 @@ class ValidSinkKind extends string { } } +/** An outdated models-as-data sink kind. */ class OutdatedSinkKind extends string { OutdatedSinkKind() { this = @@ -51,6 +52,7 @@ class OutdatedSinkKind extends string { ] } + /** Gets a replacement kind for an outdated sink kind. */ private string replacementKind() { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" @@ -84,6 +86,7 @@ class OutdatedSinkKind extends string { this = "uncontrolled-format-string" and result = "format-string" } + /** Gets an error message for an outdated sink kind. */ string outdatedMessage() { result = "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index 77dc65cf746..1b876790b37 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -264,6 +264,7 @@ module CsvValidation { ) } + /** Gets an error message relating to an invalid kind in a model. */ private string getInvalidModelKind() { exists(string row, string kind | summaryModel(row) | kind = row.splitAt(";", 8) and diff --git a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll index 40aad9caef7..9d863671941 100644 --- a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll +++ b/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes for validating kinds in models as data rows. + * Provides classes and predicates related to validating models as data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ @@ -40,6 +40,7 @@ class ValidSinkKind extends string { } } +/** An outdated models-as-data sink kind. */ class OutdatedSinkKind extends string { OutdatedSinkKind() { this = @@ -51,6 +52,7 @@ class OutdatedSinkKind extends string { ] } + /** Gets a replacement kind for an outdated sink kind. */ private string replacementKind() { this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and result = this + "-injection" @@ -84,6 +86,7 @@ class OutdatedSinkKind extends string { this = "uncontrolled-format-string" and result = "format-string" } + /** Gets an error message for an outdated sink kind. */ string outdatedMessage() { result = "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." From 6c46cd9c213351b7c0e63c85c1c956d7ab1a1fde Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 5 Jun 2023 13:11:08 -0400 Subject: [PATCH 044/364] Java/C#/Go/Swift: move 'SharedModelValidation.qll' to internal folder --- config/identical-files.json | 8 ++++---- .../ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll | 2 +- .../dataflow/{ => internal}/SharedModelValidation.qll | 0 go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 2 +- .../go/dataflow/{ => internal}/SharedModelValidation.qll | 0 java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll | 2 +- .../dataflow/{ => internal}/SharedModelValidation.qll | 0 swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll | 2 +- .../dataflow/{ => internal}/SharedModelValidation.qll | 0 9 files changed, 8 insertions(+), 8 deletions(-) rename csharp/ql/lib/semmle/code/csharp/dataflow/{ => internal}/SharedModelValidation.qll (100%) rename go/ql/lib/semmle/go/dataflow/{ => internal}/SharedModelValidation.qll (100%) rename java/ql/lib/semmle/code/java/dataflow/{ => internal}/SharedModelValidation.qll (100%) rename swift/ql/lib/codeql/swift/dataflow/{ => internal}/SharedModelValidation.qll (100%) diff --git a/config/identical-files.json b/config/identical-files.json index 800ae570bb8..52adf242dda 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -600,10 +600,10 @@ "java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll" ], "SharedModelValidation Java/C#/Go/JS/Python/Ruby/Swift": [ - "java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll", - "go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll", - "swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll", + "java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll", + "csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll", + "go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll", + "swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll", "javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll", "python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll", "ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll" diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 2093646a1f1..53cb7ead82e 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -95,7 +95,7 @@ private import internal.DataFlowPublic private import internal.FlowSummaryImpl::Public private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImplSpecific -private import SharedModelValidation +private import internal.SharedModelValidation /** Holds if a source model exists for the given parameters. */ predicate sourceModel = Extensions::sourceModel/9; diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll similarity index 100% rename from csharp/ql/lib/semmle/code/csharp/dataflow/SharedModelValidation.qll rename to csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 10146aae3b9..9dbb826c35a 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -68,7 +68,7 @@ private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImplSpecific private import internal.AccessPathSyntax private import FlowSummary -private import SharedModelValidation +private import internal.SharedModelValidation /** * A module importing the frameworks that provide external flow data, diff --git a/go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll b/go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll similarity index 100% rename from go/ql/lib/semmle/go/dataflow/SharedModelValidation.qll rename to go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 1f6e64d9b76..0a838e2fdd9 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -87,7 +87,7 @@ private import internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific private import internal.AccessPathSyntax private import ExternalFlowExtensions as Extensions private import FlowSummary -private import SharedModelValidation +private import internal.SharedModelValidation /** * A class for activating additional model rows. diff --git a/java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll b/java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll similarity index 100% rename from java/ql/lib/semmle/code/java/dataflow/SharedModelValidation.qll rename to java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index 1b876790b37..729262deef8 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -74,7 +74,7 @@ private import internal.FlowSummaryImpl::Public private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImplSpecific private import FlowSummary as FlowSummary -private import SharedModelValidation +private import internal.SharedModelValidation /** * A unit class for adding additional source model rows. diff --git a/swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll b/swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll similarity index 100% rename from swift/ql/lib/codeql/swift/dataflow/SharedModelValidation.qll rename to swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll From 7a4b74dd6a10ee3dcc507736945f45c0c781e9e8 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 5 Jun 2023 13:21:39 -0400 Subject: [PATCH 045/364] C#: fix typo with outdated sink msg location --- .../lib/semmle/code/csharp/dataflow/ExternalFlow.qll | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 53cb7ead82e..28c681e26df 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -212,13 +212,8 @@ module ModelValidation { result = "Invalid kind \"" + kind + "\" in summary model." ) or - exists(string kind | sinkModel(_, _, _, _, _, _, _, kind, _) | + exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | not kind instanceof ValidSinkKind and - result = "Invalid kind \"" + kind + "\" in sink model." - ) - or - exists(string kind, string msg | sourceModel(_, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSourceKind and msg = "Invalid kind \"" + kind + "\" in sink model." and // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. if kind instanceof OutdatedSinkKind @@ -226,6 +221,11 @@ module ModelValidation { else result = msg ) or + exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | + not kind instanceof ValidSourceKind and + result = "Invalid kind \"" + kind + "\" in source model." + ) + or exists(string kind | neutralModel(_, _, _, _, kind, _) | not kind instanceof ValidNeutralKind and result = "Invalid kind \"" + kind + "\" in neutral model." From 5a23421d9a93ca5d0b2ad2c038a85c168c8e126e Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 5 Jun 2023 13:46:56 -0400 Subject: [PATCH 046/364] Shared: minor updates to comments --- .../code/csharp/dataflow/internal/SharedModelValidation.qll | 2 +- go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll | 2 +- .../code/java/dataflow/internal/SharedModelValidation.qll | 2 +- .../javascript/frameworks/data/internal/ApiGraphModels.qll | 2 +- .../frameworks/data/internal/SharedModelValidation.qll | 2 +- .../semmle/python/frameworks/data/internal/ApiGraphModels.qll | 2 +- .../python/frameworks/data/internal/SharedModelValidation.qll | 2 +- .../lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll | 2 +- .../ruby/frameworks/data/internal/SharedModelValidation.qll | 2 +- .../codeql/swift/dataflow/internal/SharedModelValidation.qll | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll index 9d863671941..c322bc62029 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes and predicates related to validating models as data rows. + * Provides classes and predicates related to validating models-as-data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ diff --git a/go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll b/go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll index 9d863671941..c322bc62029 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes and predicates related to validating models as data rows. + * Provides classes and predicates related to validating models-as-data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll b/java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll index 9d863671941..c322bc62029 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes and predicates related to validating models as data rows. + * Provides classes and predicates related to validating models-as-data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index fe4fa8c9c2d..10bea158266 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -722,7 +722,7 @@ module ModelOutput { result = "Invalid token '" + token + "' is missing its arguments, in access path: " + path ) or - // Check for valid model kinds + // Check for invalid model kinds result = getInvalidModelKind() } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll index 9d863671941..c322bc62029 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes and predicates related to validating models as data rows. + * Provides classes and predicates related to validating models-as-data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index fe4fa8c9c2d..10bea158266 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -722,7 +722,7 @@ module ModelOutput { result = "Invalid token '" + token + "' is missing its arguments, in access path: " + path ) or - // Check for valid model kinds + // Check for invalid model kinds result = getInvalidModelKind() } } diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll index 9d863671941..c322bc62029 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes and predicates related to validating models as data rows. + * Provides classes and predicates related to validating models-as-data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index fe4fa8c9c2d..10bea158266 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -722,7 +722,7 @@ module ModelOutput { result = "Invalid token '" + token + "' is missing its arguments, in access path: " + path ) or - // Check for valid model kinds + // Check for invalid model kinds result = getInvalidModelKind() } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll index 9d863671941..c322bc62029 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes and predicates related to validating models as data rows. + * Provides classes and predicates related to validating models-as-data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll b/swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll index 9d863671941..c322bc62029 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll @@ -1,7 +1,7 @@ /** * INTERNAL: Do not use. * - * Provides classes and predicates related to validating models as data rows. + * Provides classes and predicates related to validating models-as-data rows. * Such that we can share this logic across our CodeQL analysis of different languages. */ From c994b4b9dd1d00521647d7c443dba2a20041b364 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 1 Jun 2023 17:09:34 +0100 Subject: [PATCH 047/364] Swift: Create test cases for a regular expression library. --- swift/ql/test/library-tests/regex/regex.swift | 137 ++++++++++++++++++ .../regex/regex_swift57.swift.disabled | 72 +++++++++ 2 files changed, 209 insertions(+) create mode 100644 swift/ql/test/library-tests/regex/regex.swift create mode 100644 swift/ql/test/library-tests/regex/regex_swift57.swift.disabled diff --git a/swift/ql/test/library-tests/regex/regex.swift b/swift/ql/test/library-tests/regex/regex.swift new file mode 100644 index 00000000000..edf21a2b0a5 --- /dev/null +++ b/swift/ql/test/library-tests/regex/regex.swift @@ -0,0 +1,137 @@ + +// --- stubs --- + +struct Locale { +} + +struct AnyRegexOutput { +} + +protocol RegexComponent { + associatedtype RegexOutput +} + +struct Regex : RegexComponent { + struct Match { + } + + init(_ pattern: String) throws where Output == AnyRegexOutput { } + + func firstMatch(in string: String) throws -> Regex.Match? { return nil} + func prefixMatch(in string: String) throws -> Regex.Match? { return nil} + func wholeMatch(in string: String) throws -> Regex.Match? { return nil} + + typealias RegexOutput = Output +} + +extension RangeReplaceableCollection { + mutating func replace(_ regex: some RegexComponent, with replacement: Replacement, maxReplacements: Int = .max) where Replacement : Collection, Replacement.Element == Character { } + func replacing(_ regex: some RegexComponent, with replacement: Replacement, maxReplacements: Int = .max) -> Self where Replacement: Collection, Replacement.Element == Character { return self } + mutating func trimPrefix(_ regex: some RegexComponent) { } +} + +extension StringProtocol { + func range(of aString: T, options mask:String.CompareOptions = [], range searchRange: Range? = nil, locale: Locale? = nil) -> Range? where T : StringProtocol { return nil } + func replacingOccurrences(of target: Target, with replacement: Replacement, options: String.CompareOptions = [], range searchRange: Range? = nil) -> String where Target : StringProtocol, Replacement : StringProtocol { return "" } +} + +extension String : RegexComponent { + typealias CompareOptions = NSString.CompareOptions + typealias Output = Substring + typealias RegexOutput = String.Output +} + +class NSObject { +} + +class NSString : NSObject { + struct CompareOptions : OptionSet { + var rawValue: UInt + + static var regularExpression: NSString.CompareOptions { get { return CompareOptions(rawValue: 1) } } + } + + convenience init(string aString: String) { self.init() } + + func range(of searchString: String, options mask: NSString.CompareOptions = []) -> NSRange { return NSRange(location: 0, length: 0) } + func replacingOccurrences(of target: String, with replacement: String, options: NSString.CompareOptions = [], range searchRange: NSRange) -> String { return "" } + + var length: Int { get { return 0 } } +} + +class NSMutableString : NSString { +} + +struct _NSRange { + init(location: Int, length: Int) { } +} + +typealias NSRange = _NSRange + +func NSMakeRange(_ loc: Int, _ len: Int) -> NSRange { return NSRange(location: loc, length: len) } + +class NSTextCheckingResult : NSObject { +} + +class NSRegularExpression : NSObject { + struct Options : OptionSet { + var rawValue: UInt + } + + struct MatchingOptions : OptionSet { + var rawValue: UInt + } + + init(pattern: String, options: NSRegularExpression.Options = []) throws { } + + // some types have been simplified a little here + func numberOfMatches(in string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> Int { return 0 } + func enumerateMatches(in string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange, using block: (Int, Int, Int) -> Void) { } + func matches(in string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> [NSTextCheckingResult] { return [] } + func firstMatch(in string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> NSTextCheckingResult? { return nil } + func rangeOfFirstMatch(in string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> NSRange { return NSRange(location: 0, length: 0) } + func replaceMatches(in string: NSMutableString, options: NSRegularExpression.MatchingOptions = [], range: NSRange, withTemplate templ: String) -> Int { return 0 } + func stringByReplacingMatches(in string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange, withTemplate templ: String) -> String { return "" } +} + +// --- tests --- + +func myRegexpMethodsTests() throws { + let input = "abcdef" + let regex = try Regex(".*") + + // --- Regex --- + + _ = try regex.firstMatch(in: input) + _ = try regex.prefixMatch(in: input) + _ = try regex.wholeMatch(in: input) + + // --- RangeReeplaceableCollection --- + + var inputVar = input + inputVar.replace(regex, with: "")Var + _ = input.replacing(regex, with: "") + inputVar.trimPrefix(regex)Var + + // --- StringProtocol --- + + _ = input.range(of: ".*", options: .regularExpression, range: nil, locale: nil) + _ = input.replacingOccurrences(of: ".*", with: "", options: .regularExpression) + + // --- NSRegularExpression --- + + let nsregex = try NSRegularExpression(pattern: ".*") + _ = nsregex.numberOfMatches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count)) + nsregex.enumerateMatches(in: input, range: NSMakeRange(0, input.utf16.count), using: {a, b, c in } ) + _ = nsregex.matches(in: input, range: NSMakeRange(0, input.utf16.count)) + _ = nsregex.firstMatch(in: input, range: NSMakeRange(0, input.utf16.count)) + _ = nsregex.rangeOfFirstMatch(in: input, range: NSMakeRange(0, input.utf16.count)) + _ = nsregex.replaceMatches(in: NSMutableString(string: input), range: NSMakeRange(0, input.utf16.count), withTemplate: "") + _ = nsregex.stringByReplacingMatches(in: input, range: NSMakeRange(0, input.utf16.count), withTemplate: "") + + // --- NSString --- + + let inputNS = NSString(string: "abcdef") + _ = inputNS.range(of: "*", options: .regularExpression) + _ = inputNS.replacingOccurrences(of: ".*", with: "", options: .regularExpression, range: NSMakeRange(0, inputNS.length)) +} diff --git a/swift/ql/test/library-tests/regex/regex_swift57.swift.disabled b/swift/ql/test/library-tests/regex/regex_swift57.swift.disabled new file mode 100644 index 00000000000..2d510950c26 --- /dev/null +++ b/swift/ql/test/library-tests/regex/regex_swift57.swift.disabled @@ -0,0 +1,72 @@ +// these tests require Swift 5.7 or so, and currently require the +// `-enable-bare-slash-regex` compiler flag. + +// --- stubs --- + +struct AnyRegexOutput { +} + +protocol RegexComponent { + associatedtype RegexOutput +} + +struct Regex : RegexComponent { + struct Match { + } + + init(_ pattern: String) throws where Output == AnyRegexOutput { } + + func firstMatch(in string: String) throws -> Regex.Match? { return nil } + + typealias RegexOutput = Output +} + +extension BidirectionalCollection { + func contains(_ regex: some RegexComponent) -> Bool { return false } + func firstMatch(of r: some RegexComponent) -> Regex.Match? { return nil } // slightly simplified + func firstMatch(of r: some RegexComponent) -> Regex.Match? where SubSequence == Substring { return nil } + func firstRange(of regex: some RegexComponent) -> Range? { return nil } + func matches(of r: some RegexComponent) -> [Regex.Match] { return [] } // slightly simplified + func prefixMatch(of regex: R) -> Regex.Match? where R: RegexComponent { return nil } + func ranges(of regex: some RegexComponent) -> [Range] { return [] } + func starts(with regex: some RegexComponent) -> Bool { return false } + func trimmingPrefix(_ regex: some RegexComponent) -> Self.SubSequence { return self.suffix(0) } + func split(separator: some RegexComponent, maxSplits: Int = .max, omittingEmptySubsequences: Bool = true) -> [Self.SubSequence] { return [] } +} + +extension String : RegexComponent { + typealias Output = Substring + typealias RegexOutput = String.Output +} + +// --- tests --- + +func myRegexpMethodsTests() throws { + let input = "abcdef" + let regex = try Regex(".*") + + // --- BidirectionalCollection --- + + _ = input.contains(regex) + _ = input.firstMatch(of: regex) + _ = input.firstRange(of: regex) + _ = input.matches(of: regex) + _ = input.prefixMatch(of: regex) + _ = input.ranges(of: regex) + _ = input.starts(with: regex) + _ = input.trimmingPrefix(regex) + _ = input.split(separator: regex) + + // --- compile time regexps --- + + let regex2 = /a*b*/ + _ = try regex2.firstMatch(in: input) + + let regex3 = /(?a*)*b/ + _ = try regex3.firstMatch(in: input) + + let regex4 = #/a*b*/# + _ = try regex4.firstMatch(in: input) + + _ = input.contains(/a*b*/) +} From e04f6bff279ec47980bcf65b2269873b91372bea Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:36:19 +0100 Subject: [PATCH 048/364] Swift: Add a simple Regex library. --- swift/ql/lib/codeql/swift/regex/Regex.qll | 76 +++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 swift/ql/lib/codeql/swift/regex/Regex.qll diff --git a/swift/ql/lib/codeql/swift/regex/Regex.qll b/swift/ql/lib/codeql/swift/regex/Regex.qll new file mode 100644 index 00000000000..e90df6ea1cc --- /dev/null +++ b/swift/ql/lib/codeql/swift/regex/Regex.qll @@ -0,0 +1,76 @@ +/** + * Provides classes and predicates for reasoning about use of regular expressions. + */ + +import swift + +/** + * A call that evaluates a regular expression. For example: + * ``` + * Regex("(a|b).*").firstMatch(in: myString) + * ``` + */ +abstract class RegexEval extends CallExpr { + Expr regex; + Expr input; + + /** + * Gets the regular expression that is evaluated. + */ + Expr getRegex() { result = regex } + + /** + * Gets the input string the regular expression is evaluated on. + */ + Expr getInput() { result = input } +} + +/** + * A call to a function that always evaluates a regular expression. + */ +private class AlwaysRegexEval extends RegexEval { + AlwaysRegexEval() { + this.getStaticTarget() + .(Method) + .hasQualifiedName("Regex", ["firstMatch(in:)", "prefixMatch(in:)", "wholeMatch(in:)"]) and + regex = this.getQualifier() and + input = this.getArgument(0).getExpr() + or + this.getStaticTarget() + .(Method) + .hasQualifiedName("NSRegularExpression", + [ + "numberOfMatches(in:options:range:)", "enumerateMatches(in:options:range:using:)", + "matches(in:options:range:)", "firstMatch(in:options:range:)", + "rangeOfFirstMatch(in:options:range:)", + "replaceMatches(in:options:range:withTemplate:)", + "stringByReplacingMatches(in:options:range:withTemplate:)" + ]) and + regex = this.getQualifier() and + input = this.getArgument(0).getExpr() + or + this.getStaticTarget() + .(Method) + .hasQualifiedName("BidirectionalCollection", + [ + "contains(_:)", "firstMatch(of:)", "firstRange(of:)", "matches(of:)", + "prefixMatch(of:)", "ranges(of:)", + "split(separator:maxSplits:omittingEmptySubsequences:)", "starts(with:)", + "trimmingPrefix(_:)", "wholeMatch(of:)" + ]) and + regex = this.getArgument(0).getExpr() and + input = this.getQualifier() + or + this.getStaticTarget() + .(Method) + .hasQualifiedName("RangeReplaceableCollection", + [ + "replace(_:maxReplacements:with:)", "replace(_:with:maxReplacements:)", + "replacing(_:maxReplacements:with:)", "replacing(_:subrange:maxReplacements:with:)", + "replacing(_:with:maxReplacements:)", "replacing(_:with:subrange:maxReplacements:)", + "trimPrefix(_:)" + ]) and + regex = this.getArgument(0).getExpr() and + input = this.getQualifier() + } +} From 7ab3cde3aac29624605a3727f17e8da641f2e86b Mon Sep 17 00:00:00 2001 From: yoff Date: Wed, 7 Jun 2023 13:54:31 +0200 Subject: [PATCH 049/364] Apply suggestions from code review Co-authored-by: Asger F --- ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll index 310dec3aadf..1968f6db4e8 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll @@ -1,10 +1,10 @@ /** - * Provides the implementation of a summary type tracker, that is type tracking through flow summaries. + * Provides the implementation of type tracking steps through flow summaries. * To use this, you must implement the `Input` signature. You can then use the predicates in the `Output` * signature to implement the predicates of the same names inside `TypeTrackerSpecific.qll`. */ -/** The classes and predicates needed to generate a summary type tracker. */ +/** The classes and predicates needed to generate type-tracking steps from summaries. */ signature module Input { // Dataflow nodes class Node; From 6ddf1f7eaf4eef6b36b63e6b0d93e7531603bf6c Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 7 Jun 2023 14:07:08 +0200 Subject: [PATCH 050/364] ruby/python: remove predicates from interface --- .../new/internal/SummaryTypeTracker.qll | 49 +++++++++++-------- .../new/internal/TypeTrackerSpecific.qll | 8 --- .../ruby/typetracking/SummaryTypeTracker.qll | 45 ++++++++++------- .../ruby/typetracking/TypeTrackerSpecific.qll | 15 ------ 4 files changed, 54 insertions(+), 63 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll index 310dec3aadf..4e0636826b8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll @@ -1,10 +1,10 @@ /** - * Provides the implementation of a summary type tracker, that is type tracking through flow summaries. + * Provides the implementation of type tracking steps through flow summaries. * To use this, you must implement the `Input` signature. You can then use the predicates in the `Output` * signature to implement the predicates of the same names inside `TypeTrackerSpecific.qll`. */ -/** The classes and predicates needed to generate a summary type tracker. */ +/** The classes and predicates needed to generate type-tracking steps from summaries. */ signature module Input { // Dataflow nodes class Node; @@ -80,13 +80,6 @@ signature module Input { /** Gets a dataflow node respresenting the return of `callable` indicated by `return`. */ Node returnOf(Node callable, SummaryComponent return); - // Specific summary handling - /** Holds if component should be treated as a level step by type tracking. */ - predicate componentLevelStep(SummaryComponent component); - - /** Holds if the given component can't be evaluated by `evaluateSummaryComponentStackLocal`. */ - predicate isNonLocal(SummaryComponent component); - // Relating callables to nodes /** Gets a dataflow node respresenting a call to `callable`. */ Node callTo(SummarizedCallable callable); @@ -146,8 +139,8 @@ module SummaryFlow implements Output { I::SummaryComponentStack output ) { callable.propagatesFlow(I::push(I::content(contents), input), output, true) and - not I::isNonLocal(input.head()) and - not I::isNonLocal(output.head()) + not isNonLocal(input.head()) and + not isNonLocal(output.head()) } pragma[nomagic] @@ -155,8 +148,8 @@ module SummaryFlow implements Output { I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input, I::SummaryComponentStack output ) { - not I::isNonLocal(input.head()) and - not I::isNonLocal(output.head()) and + not isNonLocal(input.head()) and + not isNonLocal(output.head()) and ( callable.propagatesFlow(input, I::push(I::content(contents), output), true) or @@ -178,8 +171,8 @@ module SummaryFlow implements Output { callable .propagatesFlow(I::push(I::content(loadContents), input), I::push(I::content(storeContents), output), true) and - not I::isNonLocal(input.head()) and - not I::isNonLocal(output.head()) + not isNonLocal(input.head()) and + not isNonLocal(output.head()) } pragma[nomagic] @@ -190,8 +183,8 @@ module SummaryFlow implements Output { exists(I::TypeTrackerContent content | callable.propagatesFlow(I::push(I::withoutContent(content), input), output, true) and filter = I::getFilterFromWithoutContentStep(content) and - not I::isNonLocal(input.head()) and - not I::isNonLocal(output.head()) and + not isNonLocal(input.head()) and + not isNonLocal(output.head()) and input != output ) } @@ -204,12 +197,26 @@ module SummaryFlow implements Output { exists(I::TypeTrackerContent content | callable.propagatesFlow(I::push(I::withContent(content), input), output, true) and filter = I::getFilterFromWithContentStep(content) and - not I::isNonLocal(input.head()) and - not I::isNonLocal(output.head()) and + not isNonLocal(input.head()) and + not isNonLocal(output.head()) and input != output ) } + private predicate componentLevelStep(I::SummaryComponent component) { + exists(I::TypeTrackerContent content | + component = I::withoutContent(content) and + not exists(I::getFilterFromWithoutContentStep(content)) + ) + } + + pragma[nomagic] + private predicate isNonLocal(I::SummaryComponent component) { + component = I::content(_) + or + component = I::withContent(_) + } + /** * Gets a data flow I::Node corresponding an argument or return value of `call`, * as specified by `component`. @@ -255,7 +262,7 @@ module SummaryFlow implements Output { I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail ) { dependsOnSummaryComponentStackCons(callable, head, tail) and - not I::isNonLocal(head) + not isNonLocal(head) } pragma[nomagic] @@ -290,7 +297,7 @@ module SummaryFlow implements Output { or result = I::returnOf(prev, head) or - I::componentLevelStep(head) and + componentLevelStep(head) and result = prev ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index 81e673dc30b..f3f9b1b52b9 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -255,14 +255,6 @@ module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getAReturnValueFlowNode() } - // Specific summary handling - predicate componentLevelStep(SummaryComponent component) { none() } - - pragma[nomagic] - predicate isNonLocal(SummaryComponent component) { - component = FlowSummary::SummaryComponent::content(_) - } - // Relating callables to nodes Node callTo(SummarizedCallable callable) { result = callable.getACallSimple() } } diff --git a/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll index 1968f6db4e8..4e0636826b8 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll @@ -80,13 +80,6 @@ signature module Input { /** Gets a dataflow node respresenting the return of `callable` indicated by `return`. */ Node returnOf(Node callable, SummaryComponent return); - // Specific summary handling - /** Holds if component should be treated as a level step by type tracking. */ - predicate componentLevelStep(SummaryComponent component); - - /** Holds if the given component can't be evaluated by `evaluateSummaryComponentStackLocal`. */ - predicate isNonLocal(SummaryComponent component); - // Relating callables to nodes /** Gets a dataflow node respresenting a call to `callable`. */ Node callTo(SummarizedCallable callable); @@ -146,8 +139,8 @@ module SummaryFlow implements Output { I::SummaryComponentStack output ) { callable.propagatesFlow(I::push(I::content(contents), input), output, true) and - not I::isNonLocal(input.head()) and - not I::isNonLocal(output.head()) + not isNonLocal(input.head()) and + not isNonLocal(output.head()) } pragma[nomagic] @@ -155,8 +148,8 @@ module SummaryFlow implements Output { I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input, I::SummaryComponentStack output ) { - not I::isNonLocal(input.head()) and - not I::isNonLocal(output.head()) and + not isNonLocal(input.head()) and + not isNonLocal(output.head()) and ( callable.propagatesFlow(input, I::push(I::content(contents), output), true) or @@ -178,8 +171,8 @@ module SummaryFlow implements Output { callable .propagatesFlow(I::push(I::content(loadContents), input), I::push(I::content(storeContents), output), true) and - not I::isNonLocal(input.head()) and - not I::isNonLocal(output.head()) + not isNonLocal(input.head()) and + not isNonLocal(output.head()) } pragma[nomagic] @@ -190,8 +183,8 @@ module SummaryFlow implements Output { exists(I::TypeTrackerContent content | callable.propagatesFlow(I::push(I::withoutContent(content), input), output, true) and filter = I::getFilterFromWithoutContentStep(content) and - not I::isNonLocal(input.head()) and - not I::isNonLocal(output.head()) and + not isNonLocal(input.head()) and + not isNonLocal(output.head()) and input != output ) } @@ -204,12 +197,26 @@ module SummaryFlow implements Output { exists(I::TypeTrackerContent content | callable.propagatesFlow(I::push(I::withContent(content), input), output, true) and filter = I::getFilterFromWithContentStep(content) and - not I::isNonLocal(input.head()) and - not I::isNonLocal(output.head()) and + not isNonLocal(input.head()) and + not isNonLocal(output.head()) and input != output ) } + private predicate componentLevelStep(I::SummaryComponent component) { + exists(I::TypeTrackerContent content | + component = I::withoutContent(content) and + not exists(I::getFilterFromWithoutContentStep(content)) + ) + } + + pragma[nomagic] + private predicate isNonLocal(I::SummaryComponent component) { + component = I::content(_) + or + component = I::withContent(_) + } + /** * Gets a data flow I::Node corresponding an argument or return value of `call`, * as specified by `component`. @@ -255,7 +262,7 @@ module SummaryFlow implements Output { I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail ) { dependsOnSummaryComponentStackCons(callable, head, tail) and - not I::isNonLocal(head) + not isNonLocal(head) } pragma[nomagic] @@ -290,7 +297,7 @@ module SummaryFlow implements Output { or result = I::returnOf(prev, head) or - I::componentLevelStep(head) and + componentLevelStep(head) and result = prev ) } diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll index 4f17302e72b..4283521afc5 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll @@ -467,21 +467,6 @@ module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { ) } - // Specific summary handling - predicate componentLevelStep(SummaryComponent component) { - exists(TypeTrackerContent content | - component = SummaryComponent::withoutContent(content) and - not exists(getFilterFromWithoutContentStep(content)) - ) - } - - pragma[nomagic] - predicate isNonLocal(SummaryComponent component) { - component = SC::content(_) - or - component = SC::withContent(_) - } - // Relating callables to nodes Node callTo(SummarizedCallable callable) { result.asExpr().getExpr() = callable.getACallSimple() } } From 57508b2b3b7623eec9924d983ea1e8ec68200401 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 30 May 2023 13:30:05 +0100 Subject: [PATCH 051/364] ruby: Limit rack PotentialResponseNode to things that look like they occur in a rack application --- ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll | 2 +- .../ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll index 78666b7fe1d..35a12c8e3eb 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll @@ -30,7 +30,7 @@ module App { AppCandidate() { call = this.getInstanceMethod("call") and call.getNumberOfParameters() = 1 and - call.getReturn() = trackRackResponse(resp) + call.getAReturningNode() = trackRackResponse(resp) } /** diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll index 65322dbac05..983d50aaeec 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll @@ -19,7 +19,10 @@ module Private { class PotentialResponseNode extends DataFlow::ArrayLiteralNode { // [status, headers, body] - PotentialResponseNode() { this.getNumberOfArguments() = 3 } + PotentialResponseNode() { + this.getNumberOfArguments() = 3 and + this.asExpr().getExpr().getEnclosingModule+().getAMethod().getName() = "call" + } /** * Gets an HTTP status code that may be returned in this response. From a5d8db6317d99656ab15993ebfcdf6a050905596 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 7 Jun 2023 15:55:01 +0100 Subject: [PATCH 052/364] Ruby: fix qldoc --- ruby/ql/lib/codeql/ruby/frameworks/Rack.qll | 4 ++++ ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll | 4 ++++ ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll | 7 ++++++- .../lib/codeql/ruby/frameworks/rack/internal/Response.qll | 6 ++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll index 64ca7cc0b60..74553476d17 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll @@ -1,3 +1,7 @@ +/** + * Provides modeling for the Rack library. + */ + /** * Provides modeling for the Rack library. */ diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll index 35a12c8e3eb..0a344f46dc8 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll @@ -1,3 +1,7 @@ +/** + * Provides modeling for Rack applications. + */ + private import codeql.ruby.ApiGraphs private import codeql.ruby.DataFlow private import codeql.ruby.typetracking.TypeTracker diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll index d40895a2f13..2aceebffbcd 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll @@ -1,3 +1,7 @@ +/** + * Provides modeling for the `Mime` component of the `Rack` library. + */ + private import codeql.ruby.ApiGraphs private import codeql.ruby.DataFlow @@ -1288,7 +1292,7 @@ private predicate mimeTypeMatches(string ext, string mimeType) { } /** - * Provides modeling for the `Response` component of the `Rack` library. + * Provides modeling for the `Mime` component of the `Rack` library. */ module Mime { class MimetypeCall extends DataFlow::CallNode { @@ -1300,6 +1304,7 @@ module Mime { result = this.getArgument(0).getConstantValue().getStringlikeValue() } + /** Gets the canonical MIME type string returned by this call. */ string getMimeType() { mimeTypeMatches(this.getExtension(), result) } } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll index 983d50aaeec..26162a8d306 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll @@ -1,3 +1,7 @@ +/** + * Provides modeling for the `Response` component of the `Rack` library. + */ + private import codeql.ruby.AST private import codeql.ruby.ApiGraphs private import codeql.ruby.Concepts @@ -17,6 +21,7 @@ module Private { private DataFlow::Node trackInt(int i) { trackInt(TypeTracker::end(), i).flowsTo(result) } + /** A `DataFlow::Node` that may be a rack response. This is detected heuristically, if something "looks like" a rack response syntactically then we consider it to be a potential response node. */ class PotentialResponseNode extends DataFlow::ArrayLiteralNode { // [status, headers, body] PotentialResponseNode() { @@ -83,6 +88,7 @@ module Public { override string getMimetypeDefault() { none() } } + /** A `DataFlow::Node` returned from a rack request that has a redirect HTTP status code. */ class RedirectResponse extends ResponseNode, Http::Server::HttpRedirectResponse::Range { RedirectResponse() { this.getAStatusCode() = [300, 301, 302, 303, 307, 308] } From 0a7ae587101b857557a82ea3aafb14c4310c2bdb Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 7 Jun 2023 16:30:53 +0100 Subject: [PATCH 053/364] Ruby: revert to simpler Rack PotentialResponseNode def and use TypeBackTracker to track instances --- .../ruby/frameworks/rack/internal/App.qll | 25 +++++++++++-------- .../frameworks/rack/internal/Response.qll | 5 +--- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll index 0a344f46dc8..eb8b283fa16 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll @@ -7,15 +7,20 @@ private import codeql.ruby.DataFlow private import codeql.ruby.typetracking.TypeTracker private import Response::Private as RP -private DataFlow::LocalSourceNode trackRackResponse(TypeTracker t, RP::PotentialResponseNode n) { - t.start() and - result = n - or - exists(TypeTracker t2 | result = trackRackResponse(t2, n).track(t2, t)) +/** A method node for a method named `call`. */ +private class CallMethodNode extends DataFlow::MethodNode { + CallMethodNode() { this.getMethodName() = "call" } } -private DataFlow::Node trackRackResponse(RP::PotentialResponseNode n) { - trackRackResponse(TypeTracker::end(), n).flowsTo(result) +private DataFlow::LocalSourceNode trackRackResponse(TypeBackTracker t, CallMethodNode call) { + t.start() and + result = call.getAReturningNode() + or + exists(TypeBackTracker t2 | result = trackRackResponse(t2, call).backtrack(t2, t)) +} + +private RP::PotentialResponseNode trackRackResponse(CallMethodNode call) { + result = trackRackResponse(TypeBackTracker::end(), call) } /** @@ -28,13 +33,13 @@ module App { * (traditionally called `env`) and returns a rack-compatible response. */ class AppCandidate extends DataFlow::ClassNode { - private DataFlow::MethodNode call; + private CallMethodNode call; private RP::PotentialResponseNode resp; AppCandidate() { call = this.getInstanceMethod("call") and call.getNumberOfParameters() = 1 and - call.getAReturningNode() = trackRackResponse(resp) + resp = trackRackResponse(call) } /** @@ -42,7 +47,7 @@ module App { */ DataFlow::ParameterNode getEnv() { result = call.getParameter(0) } - /** Gets the response returned from the request. */ + /** Gets the response returned from a request to this application. */ RP::PotentialResponseNode getResponse() { result = resp } } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll index 26162a8d306..d5ca488fcda 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll @@ -24,10 +24,7 @@ module Private { /** A `DataFlow::Node` that may be a rack response. This is detected heuristically, if something "looks like" a rack response syntactically then we consider it to be a potential response node. */ class PotentialResponseNode extends DataFlow::ArrayLiteralNode { // [status, headers, body] - PotentialResponseNode() { - this.getNumberOfArguments() = 3 and - this.asExpr().getExpr().getEnclosingModule+().getAMethod().getName() = "call" - } + PotentialResponseNode() { this.getNumberOfArguments() = 3 } /** * Gets an HTTP status code that may be returned in this response. From c493e276eccbcefddf28ae58cb7b7accdf41edc2 Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Thu, 8 Jun 2023 10:57:12 +0100 Subject: [PATCH 054/364] Update MaD sink kinds from main --- csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 0ce50e54a3a..22335fb0dce 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -213,8 +213,9 @@ module ModelValidation { exists(string kind | sinkModel(_, _, _, _, _, _, _, kind, _) | not kind = [ - "code", "command-injection", "html", "ldap-injection", "log-injection", "remote", "sql", - "url-redirection", "xss", + "code-injection", "command-injection", "file-content-store", "html-injection", + "ldap-injection", "log-injection", "remote", "sql-injection", "url-redirection", + "js-injection", ] and not kind.matches("encryption-%") and result = "Invalid kind \"" + kind + "\" in sink model." From c531b94594c782d1a0e67f4bb4839b03104c2d49 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 8 Jun 2023 11:59:10 +0100 Subject: [PATCH 055/364] Ruby: add a change note for rack redirect support --- ruby/ql/lib/change-notes/2023-06-08-rack-redirect.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ruby/ql/lib/change-notes/2023-06-08-rack-redirect.md diff --git a/ruby/ql/lib/change-notes/2023-06-08-rack-redirect.md b/ruby/ql/lib/change-notes/2023-06-08-rack-redirect.md new file mode 100644 index 00000000000..09687fa95be --- /dev/null +++ b/ruby/ql/lib/change-notes/2023-06-08-rack-redirect.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* HTTP redirect responses from Rack applications are now recognized as a potential sink for open redirect alerts. From 21b4f885a634ca921089e0f79e566a744594785b Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 8 Jun 2023 12:01:42 +0100 Subject: [PATCH 056/364] ruby: fix qldoc --- ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll index 2aceebffbcd..f9bd42c15b0 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll @@ -1295,6 +1295,7 @@ private predicate mimeTypeMatches(string ext, string mimeType) { * Provides modeling for the `Mime` component of the `Rack` library. */ module Mime { + /** A call to `Rack::Mime.mime_type`. This method maps file extensions to MIME types. */ class MimetypeCall extends DataFlow::CallNode { MimetypeCall() { this = API::getTopLevelMember("Rack").getMember("Mime").getAMethodCall("mime_type") From b4620042a5c356f84c726e9c68edb65d294e61cb Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 8 Jun 2023 12:09:22 +0100 Subject: [PATCH 057/364] Ruby: fix use of deprecated predicate --- ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll index eb8b283fa16..5ea8ad38f29 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll @@ -14,7 +14,7 @@ private class CallMethodNode extends DataFlow::MethodNode { private DataFlow::LocalSourceNode trackRackResponse(TypeBackTracker t, CallMethodNode call) { t.start() and - result = call.getAReturningNode() + result = call.getAReturnNode() or exists(TypeBackTracker t2 | result = trackRackResponse(t2, call).backtrack(t2, t)) } From e4be303a2359917aadf855ead7f38f67a7a86654 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 8 Jun 2023 19:57:37 +0000 Subject: [PATCH 058/364] Release preparation for version 2.13.4 --- cpp/ql/lib/CHANGELOG.md | 8 +++ .../0.7.3.md} | 9 +-- cpp/ql/lib/codeql-pack.release.yml | 2 +- cpp/ql/lib/qlpack.yml | 2 +- cpp/ql/src/CHANGELOG.md | 6 ++ .../0.6.3.md} | 7 ++- cpp/ql/src/codeql-pack.release.yml | 2 +- cpp/ql/src/qlpack.yml | 2 +- .../ql/campaigns/Solorigate/lib/CHANGELOG.md | 4 ++ .../lib/change-notes/released/1.5.3.md | 3 + .../Solorigate/lib/codeql-pack.release.yml | 2 +- csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +- .../ql/campaigns/Solorigate/src/CHANGELOG.md | 4 ++ .../src/change-notes/released/1.5.3.md | 3 + .../Solorigate/src/codeql-pack.release.yml | 2 +- csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +- csharp/ql/lib/CHANGELOG.md | 21 +++++++ .../2023-05-17-update-csharp-sink-kinds.md | 9 --- .../2023-05-30-source-generators.md | 4 -- .../lib/change-notes/2023-06-06-dotnettest.md | 4 -- .../0.6.3.md} | 18 +++++- csharp/ql/lib/codeql-pack.release.yml | 2 +- csharp/ql/lib/qlpack.yml | 2 +- csharp/ql/src/CHANGELOG.md | 4 ++ csharp/ql/src/change-notes/released/0.6.3.md | 3 + csharp/ql/src/codeql-pack.release.yml | 2 +- csharp/ql/src/qlpack.yml | 2 +- go/ql/lib/CHANGELOG.md | 4 ++ go/ql/lib/change-notes/released/0.5.3.md | 3 + go/ql/lib/codeql-pack.release.yml | 2 +- go/ql/lib/qlpack.yml | 2 +- go/ql/src/CHANGELOG.md | 4 ++ go/ql/src/change-notes/released/0.5.3.md | 3 + go/ql/src/codeql-pack.release.yml | 2 +- go/ql/src/qlpack.yml | 2 +- java/ql/lib/CHANGELOG.md | 58 +++++++++++++++++++ .../2023-05-05-java-sink-kind-revamp.md | 22 ------- ...-12-androidwidget-source-kind-to-remote.md | 4 -- ...7-change-hostnamesanitizingprefix-regex.md | 5 -- .../2023-05-19-path-injection-sinks-mad.md | 4 -- ...023-05-22-inputstreamwrapper-transitive.md | 4 -- ...3-java-nio-file-files-copy-models-tweak.md | 4 -- .../change-notes/2023-05-24-kotlin-1.9.0.md | 4 -- .../2023-05-26-play-framework-models.md | 4 -- .../change-notes/2023-05-30-gson-models.md | 4 -- .../lib/change-notes/2023-05-30-new-models.md | 6 -- .../lib/change-notes/2023-06-01-new-models.md | 7 --- .../change-notes/2023-06-02-delete-deps.md | 6 -- .../2023-06-06-kotlin-use-with-flow.md | 4 -- .../lib/change-notes/2023-06-06-new-models.md | 15 ----- java/ql/lib/change-notes/released/0.6.3.md | 57 ++++++++++++++++++ java/ql/lib/codeql-pack.release.yml | 2 +- java/ql/lib/qlpack.yml | 2 +- java/ql/src/CHANGELOG.md | 6 ++ .../0.6.3.md} | 7 ++- java/ql/src/codeql-pack.release.yml | 2 +- java/ql/src/qlpack.yml | 2 +- javascript/ql/lib/CHANGELOG.md | 20 +++++++ .../change-notes/2023-04-19-typescript-5-1.md | 4 -- .../change-notes/2023-04-30-npm-submodule.md | 5 -- .../2023-05-12-update-js-sink-kinds.md | 6 -- .../0.6.3.md} | 17 ++++-- javascript/ql/lib/codeql-pack.release.yml | 2 +- javascript/ql/lib/qlpack.yml | 2 +- javascript/ql/src/CHANGELOG.md | 8 +++ .../0.6.3.md} | 7 ++- javascript/ql/src/codeql-pack.release.yml | 2 +- javascript/ql/src/qlpack.yml | 2 +- misc/suite-helpers/CHANGELOG.md | 4 ++ .../change-notes/released/0.5.3.md | 3 + misc/suite-helpers/codeql-pack.release.yml | 2 +- misc/suite-helpers/qlpack.yml | 2 +- python/ql/lib/CHANGELOG.md | 4 ++ python/ql/lib/change-notes/released/0.9.3.md | 3 + python/ql/lib/codeql-pack.release.yml | 2 +- python/ql/lib/qlpack.yml | 2 +- python/ql/src/CHANGELOG.md | 6 ++ .../0.7.3.md} | 9 +-- python/ql/src/codeql-pack.release.yml | 2 +- python/ql/src/qlpack.yml | 2 +- ruby/ql/lib/CHANGELOG.md | 12 ++++ ruby/ql/lib/change-notes/2023-05-06-mysql2.md | 4 -- ruby/ql/lib/change-notes/2023-05-06-pg.md | 4 -- ruby/ql/lib/change-notes/2023-05-07-sequel.md | 4 -- .../change-notes/2023-06-02-delete-deps.md | 7 --- ruby/ql/lib/change-notes/released/0.6.3.md | 11 ++++ ruby/ql/lib/codeql-pack.release.yml | 2 +- ruby/ql/lib/qlpack.yml | 2 +- ruby/ql/src/CHANGELOG.md | 10 ++++ .../2023-05-24-delete-name-clash.md | 5 -- .../0.6.3.md} | 9 ++- ruby/ql/src/codeql-pack.release.yml | 2 +- ruby/ql/src/qlpack.yml | 2 +- shared/regex/CHANGELOG.md | 4 ++ shared/regex/change-notes/released/0.0.14.md | 3 + shared/regex/codeql-pack.release.yml | 2 +- shared/regex/qlpack.yml | 2 +- shared/ssa/CHANGELOG.md | 4 ++ shared/ssa/change-notes/released/0.0.18.md | 3 + shared/ssa/codeql-pack.release.yml | 2 +- shared/ssa/qlpack.yml | 2 +- shared/tutorial/CHANGELOG.md | 4 ++ .../tutorial/change-notes/released/0.0.11.md | 3 + shared/tutorial/codeql-pack.release.yml | 2 +- shared/tutorial/qlpack.yml | 2 +- shared/typetracking/CHANGELOG.md | 4 ++ .../change-notes/released/0.0.11.md | 3 + shared/typetracking/codeql-pack.release.yml | 2 +- shared/typetracking/qlpack.yml | 2 +- shared/typos/CHANGELOG.md | 4 ++ shared/typos/change-notes/released/0.0.18.md | 3 + shared/typos/codeql-pack.release.yml | 2 +- shared/typos/qlpack.yml | 2 +- shared/util/CHANGELOG.md | 4 ++ shared/util/change-notes/released/0.0.11.md | 3 + shared/util/codeql-pack.release.yml | 2 +- shared/util/qlpack.yml | 2 +- shared/yaml/CHANGELOG.md | 4 ++ shared/yaml/change-notes/released/0.0.3.md | 3 + shared/yaml/codeql-pack.release.yml | 2 +- shared/yaml/qlpack.yml | 2 +- 121 files changed, 425 insertions(+), 224 deletions(-) rename cpp/ql/lib/change-notes/{2022-08-06-delete-deps.md => released/0.7.3.md} (71%) rename cpp/ql/src/change-notes/{2023-05-24-overrun-write-query.md => released/0.6.3.md} (80%) create mode 100644 csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.5.3.md create mode 100644 csharp/ql/campaigns/Solorigate/src/change-notes/released/1.5.3.md delete mode 100644 csharp/ql/lib/change-notes/2023-05-17-update-csharp-sink-kinds.md delete mode 100644 csharp/ql/lib/change-notes/2023-05-30-source-generators.md delete mode 100644 csharp/ql/lib/change-notes/2023-06-06-dotnettest.md rename csharp/ql/lib/change-notes/{2023-06-02-delete-deps.md => released/0.6.3.md} (50%) create mode 100644 csharp/ql/src/change-notes/released/0.6.3.md create mode 100644 go/ql/lib/change-notes/released/0.5.3.md create mode 100644 go/ql/src/change-notes/released/0.5.3.md delete mode 100644 java/ql/lib/change-notes/2023-05-05-java-sink-kind-revamp.md delete mode 100644 java/ql/lib/change-notes/2023-05-12-androidwidget-source-kind-to-remote.md delete mode 100644 java/ql/lib/change-notes/2023-05-17-change-hostnamesanitizingprefix-regex.md delete mode 100644 java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md delete mode 100644 java/ql/lib/change-notes/2023-05-22-inputstreamwrapper-transitive.md delete mode 100644 java/ql/lib/change-notes/2023-05-23-java-nio-file-files-copy-models-tweak.md delete mode 100644 java/ql/lib/change-notes/2023-05-24-kotlin-1.9.0.md delete mode 100644 java/ql/lib/change-notes/2023-05-26-play-framework-models.md delete mode 100644 java/ql/lib/change-notes/2023-05-30-gson-models.md delete mode 100644 java/ql/lib/change-notes/2023-05-30-new-models.md delete mode 100644 java/ql/lib/change-notes/2023-06-01-new-models.md delete mode 100644 java/ql/lib/change-notes/2023-06-02-delete-deps.md delete mode 100644 java/ql/lib/change-notes/2023-06-06-kotlin-use-with-flow.md delete mode 100644 java/ql/lib/change-notes/2023-06-06-new-models.md create mode 100644 java/ql/lib/change-notes/released/0.6.3.md rename java/ql/src/change-notes/{2023-06-05-lines-of-code.md => released/0.6.3.md} (77%) delete mode 100644 javascript/ql/lib/change-notes/2023-04-19-typescript-5-1.md delete mode 100644 javascript/ql/lib/change-notes/2023-04-30-npm-submodule.md delete mode 100644 javascript/ql/lib/change-notes/2023-05-12-update-js-sink-kinds.md rename javascript/ql/lib/change-notes/{2023-06-02-delete-deps.md => released/0.6.3.md} (64%) rename javascript/ql/src/change-notes/{2023-06-01-restrict-regex-search-function.md => released/0.6.3.md} (90%) create mode 100644 misc/suite-helpers/change-notes/released/0.5.3.md create mode 100644 python/ql/lib/change-notes/released/0.9.3.md rename python/ql/src/change-notes/{2023-06-02-unsafe-deserialization-name-update.md => released/0.7.3.md} (81%) delete mode 100644 ruby/ql/lib/change-notes/2023-05-06-mysql2.md delete mode 100644 ruby/ql/lib/change-notes/2023-05-06-pg.md delete mode 100644 ruby/ql/lib/change-notes/2023-05-07-sequel.md delete mode 100644 ruby/ql/lib/change-notes/2023-06-02-delete-deps.md create mode 100644 ruby/ql/lib/change-notes/released/0.6.3.md delete mode 100644 ruby/ql/src/change-notes/2023-05-24-delete-name-clash.md rename ruby/ql/src/change-notes/{2023-05-26-super-and-flow-through.md => released/0.6.3.md} (57%) create mode 100644 shared/regex/change-notes/released/0.0.14.md create mode 100644 shared/ssa/change-notes/released/0.0.18.md create mode 100644 shared/tutorial/change-notes/released/0.0.11.md create mode 100644 shared/typetracking/change-notes/released/0.0.11.md create mode 100644 shared/typos/change-notes/released/0.0.18.md create mode 100644 shared/util/change-notes/released/0.0.11.md create mode 100644 shared/yaml/change-notes/released/0.0.3.md diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md index e5d2ae643bc..e990e830005 100644 --- a/cpp/ql/lib/CHANGELOG.md +++ b/cpp/ql/lib/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.7.3 + +### Minor Analysis Improvements + +* Deleted the deprecated `hasCopyConstructor` predicate from the `Class` class in `Class.qll`. +* Deleted many deprecated predicates and classes with uppercase `AST`, `SSA`, `CFG`, `API`, etc. in their names. Use the PascalCased versions instead. +* Deleted the deprecated `CodeDuplication.qll` file. + ## 0.7.2 ### New Features diff --git a/cpp/ql/lib/change-notes/2022-08-06-delete-deps.md b/cpp/ql/lib/change-notes/released/0.7.3.md similarity index 71% rename from cpp/ql/lib/change-notes/2022-08-06-delete-deps.md rename to cpp/ql/lib/change-notes/released/0.7.3.md index c234c189484..d6cb19b669d 100644 --- a/cpp/ql/lib/change-notes/2022-08-06-delete-deps.md +++ b/cpp/ql/lib/change-notes/released/0.7.3.md @@ -1,6 +1,7 @@ ---- -category: minorAnalysis ---- +## 0.7.3 + +### Minor Analysis Improvements + * Deleted the deprecated `hasCopyConstructor` predicate from the `Class` class in `Class.qll`. * Deleted many deprecated predicates and classes with uppercase `AST`, `SSA`, `CFG`, `API`, etc. in their names. Use the PascalCased versions instead. -* Deleted the deprecated `CodeDuplication.qll` file. \ No newline at end of file +* Deleted the deprecated `CodeDuplication.qll` file. diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml index fee171e9685..a4ea9c8de17 100644 --- a/cpp/ql/lib/codeql-pack.release.yml +++ b/cpp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.7.2 +lastReleaseVersion: 0.7.3 diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 1982886c434..2d39cafe571 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 0.7.3-dev +version: 0.7.3 groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md index 4991b66538f..ca314dcd6d7 100644 --- a/cpp/ql/src/CHANGELOG.md +++ b/cpp/ql/src/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.6.3 + +### New Queries + +* Added a new query, `cpp/overrun-write`, to detect buffer overflows in C-style functions that manipulate buffers. + ## 0.6.2 No user-facing changes. diff --git a/cpp/ql/src/change-notes/2023-05-24-overrun-write-query.md b/cpp/ql/src/change-notes/released/0.6.3.md similarity index 80% rename from cpp/ql/src/change-notes/2023-05-24-overrun-write-query.md rename to cpp/ql/src/change-notes/released/0.6.3.md index 32195223fcd..d9421d55250 100644 --- a/cpp/ql/src/change-notes/2023-05-24-overrun-write-query.md +++ b/cpp/ql/src/change-notes/released/0.6.3.md @@ -1,4 +1,5 @@ ---- -category: newQuery ---- +## 0.6.3 + +### New Queries + * Added a new query, `cpp/overrun-write`, to detect buffer overflows in C-style functions that manipulate buffers. diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml index 5501a2a1cc5..b7dafe32c5d 100644 --- a/cpp/ql/src/codeql-pack.release.yml +++ b/cpp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.2 +lastReleaseVersion: 0.6.3 diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index 46dffc3e763..1aa38f466f6 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 0.6.3-dev +version: 0.6.3 groups: - cpp - queries diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md index ad7a007007f..b466881d9d7 100644 --- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.5.3 + +No user-facing changes. + ## 1.5.2 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.5.3.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.5.3.md new file mode 100644 index 00000000000..2e9bcb5e663 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.5.3.md @@ -0,0 +1,3 @@ +## 1.5.3 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml index 7eb901bae56..232224b0e26 100644 --- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.5.2 +lastReleaseVersion: 1.5.3 diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 4f2900e0b73..d48f3cb1b0a 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.5.3-dev +version: 1.5.3 groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md index ad7a007007f..b466881d9d7 100644 --- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.5.3 + +No user-facing changes. + ## 1.5.2 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.5.3.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.5.3.md new file mode 100644 index 00000000000..2e9bcb5e663 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.5.3.md @@ -0,0 +1,3 @@ +## 1.5.3 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml index 7eb901bae56..232224b0e26 100644 --- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.5.2 +lastReleaseVersion: 1.5.3 diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index 2318576e19e..f63efb58811 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.5.3-dev +version: 1.5.3 groups: - csharp - solorigate diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md index 435255a997a..8fc9f20a131 100644 --- a/csharp/ql/lib/CHANGELOG.md +++ b/csharp/ql/lib/CHANGELOG.md @@ -1,3 +1,24 @@ +## 0.6.3 + +### Major Analysis Improvements + +* The extractor has been changed to run after the traced compiler call. This allows inspecting compiler generated files, such as the output of source generators. With this change, `.cshtml` files and their generated `.cshtml.g.cs` counterparts are extracted on dotnet 6 and above. + +### Minor Analysis Improvements + +* C#: Analysis of the `dotnet test` command supplied with a `dll` or `exe` file as argument no longer fails due to the addition of an erroneous `-p:SharedCompilation=false` argument. +* Deleted the deprecated `WebConfigXML`, `ConfigurationXMLElement`, `LocationXMLElement`, `SystemWebXMLElement`, `SystemWebServerXMLElement`, `CustomErrorsXMLElement`, and `HttpRuntimeXMLElement` classes from `WebConfig.qll`. The non-deprecated names with PascalCased Xml suffixes should be used instead. +* Deleted the deprecated `Record` class from both `Types.qll` and `Type.qll`. +* Deleted the deprecated `StructuralComparisonConfiguration` class from `StructuralComparison.qll`, use `sameGvn` instead. +* Deleted the deprecated `isParameterOf` predicate from the `ParameterNode` class. +* Deleted the deprecated `SafeExternalAPICallable`, `ExternalAPIDataNode`, `UntrustedDataToExternalAPIConfig`, `UntrustedExternalAPIDataNode`, and `ExternalAPIUsedWithUntrustedData` classes from `ExternalAPIsQuery.qll`. The non-deprecated names with PascalCased Api suffixes should be used instead. +* Updated the following C# sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working. + * `code` to `code-injection` + * `sql` to `sql-injection` + * `html` to `html-injection` + * `xss` to `js-injection` + * `remote` to `file-content-store` + ## 0.6.2 ### Minor Analysis Improvements diff --git a/csharp/ql/lib/change-notes/2023-05-17-update-csharp-sink-kinds.md b/csharp/ql/lib/change-notes/2023-05-17-update-csharp-sink-kinds.md deleted file mode 100644 index ce6d618af5e..00000000000 --- a/csharp/ql/lib/change-notes/2023-05-17-update-csharp-sink-kinds.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -category: minorAnalysis ---- -* Updated the following C# sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working. - * `code` to `code-injection` - * `sql` to `sql-injection` - * `html` to `html-injection` - * `xss` to `js-injection` - * `remote` to `file-content-store` diff --git a/csharp/ql/lib/change-notes/2023-05-30-source-generators.md b/csharp/ql/lib/change-notes/2023-05-30-source-generators.md deleted file mode 100644 index 5483ce6af35..00000000000 --- a/csharp/ql/lib/change-notes/2023-05-30-source-generators.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: majorAnalysis ---- -* The extractor has been changed to run after the traced compiler call. This allows inspecting compiler generated files, such as the output of source generators. With this change, `.cshtml` files and their generated `.cshtml.g.cs` counterparts are extracted on dotnet 6 and above. diff --git a/csharp/ql/lib/change-notes/2023-06-06-dotnettest.md b/csharp/ql/lib/change-notes/2023-06-06-dotnettest.md deleted file mode 100644 index e7179b93189..00000000000 --- a/csharp/ql/lib/change-notes/2023-06-06-dotnettest.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* C#: Analysis of the `dotnet test` command supplied with a `dll` or `exe` file as argument no longer fails due to the addition of an erroneous `-p:SharedCompilation=false` argument. \ No newline at end of file diff --git a/csharp/ql/lib/change-notes/2023-06-02-delete-deps.md b/csharp/ql/lib/change-notes/released/0.6.3.md similarity index 50% rename from csharp/ql/lib/change-notes/2023-06-02-delete-deps.md rename to csharp/ql/lib/change-notes/released/0.6.3.md index 13402f08147..51f62426686 100644 --- a/csharp/ql/lib/change-notes/2023-06-02-delete-deps.md +++ b/csharp/ql/lib/change-notes/released/0.6.3.md @@ -1,8 +1,20 @@ ---- -category: minorAnalysis ---- +## 0.6.3 + +### Major Analysis Improvements + +* The extractor has been changed to run after the traced compiler call. This allows inspecting compiler generated files, such as the output of source generators. With this change, `.cshtml` files and their generated `.cshtml.g.cs` counterparts are extracted on dotnet 6 and above. + +### Minor Analysis Improvements + +* C#: Analysis of the `dotnet test` command supplied with a `dll` or `exe` file as argument no longer fails due to the addition of an erroneous `-p:SharedCompilation=false` argument. * Deleted the deprecated `WebConfigXML`, `ConfigurationXMLElement`, `LocationXMLElement`, `SystemWebXMLElement`, `SystemWebServerXMLElement`, `CustomErrorsXMLElement`, and `HttpRuntimeXMLElement` classes from `WebConfig.qll`. The non-deprecated names with PascalCased Xml suffixes should be used instead. * Deleted the deprecated `Record` class from both `Types.qll` and `Type.qll`. * Deleted the deprecated `StructuralComparisonConfiguration` class from `StructuralComparison.qll`, use `sameGvn` instead. * Deleted the deprecated `isParameterOf` predicate from the `ParameterNode` class. * Deleted the deprecated `SafeExternalAPICallable`, `ExternalAPIDataNode`, `UntrustedDataToExternalAPIConfig`, `UntrustedExternalAPIDataNode`, and `ExternalAPIUsedWithUntrustedData` classes from `ExternalAPIsQuery.qll`. The non-deprecated names with PascalCased Api suffixes should be used instead. +* Updated the following C# sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working. + * `code` to `code-injection` + * `sql` to `sql-injection` + * `html` to `html-injection` + * `xss` to `js-injection` + * `remote` to `file-content-store` diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml index 5501a2a1cc5..b7dafe32c5d 100644 --- a/csharp/ql/lib/codeql-pack.release.yml +++ b/csharp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.2 +lastReleaseVersion: 0.6.3 diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 17e00fa022c..833f7eae10b 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 0.6.3-dev +version: 0.6.3 groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md index e214ec42a03..8e82ab07313 100644 --- a/csharp/ql/src/CHANGELOG.md +++ b/csharp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.3 + +No user-facing changes. + ## 0.6.2 No user-facing changes. diff --git a/csharp/ql/src/change-notes/released/0.6.3.md b/csharp/ql/src/change-notes/released/0.6.3.md new file mode 100644 index 00000000000..83374bcef56 --- /dev/null +++ b/csharp/ql/src/change-notes/released/0.6.3.md @@ -0,0 +1,3 @@ +## 0.6.3 + +No user-facing changes. diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml index 5501a2a1cc5..b7dafe32c5d 100644 --- a/csharp/ql/src/codeql-pack.release.yml +++ b/csharp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.2 +lastReleaseVersion: 0.6.3 diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index 95506e0f254..0ae9d1d6c03 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 0.6.3-dev +version: 0.6.3 groups: - csharp - queries diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md index 5f09272c19b..0e0d00161e1 100644 --- a/go/ql/lib/CHANGELOG.md +++ b/go/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.3 + +No user-facing changes. + ## 0.5.2 ### Minor Analysis Improvements diff --git a/go/ql/lib/change-notes/released/0.5.3.md b/go/ql/lib/change-notes/released/0.5.3.md new file mode 100644 index 00000000000..e97503053f0 --- /dev/null +++ b/go/ql/lib/change-notes/released/0.5.3.md @@ -0,0 +1,3 @@ +## 0.5.3 + +No user-facing changes. diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/go/ql/lib/codeql-pack.release.yml +++ b/go/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index 287c27187e3..ce44cff6d9e 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 0.5.3-dev +version: 0.5.3 groups: go dbscheme: go.dbscheme extractor: go diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md index 8a1b8bcfebc..61712c5e790 100644 --- a/go/ql/src/CHANGELOG.md +++ b/go/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.3 + +No user-facing changes. + ## 0.5.2 No user-facing changes. diff --git a/go/ql/src/change-notes/released/0.5.3.md b/go/ql/src/change-notes/released/0.5.3.md new file mode 100644 index 00000000000..e97503053f0 --- /dev/null +++ b/go/ql/src/change-notes/released/0.5.3.md @@ -0,0 +1,3 @@ +## 0.5.3 + +No user-facing changes. diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/go/ql/src/codeql-pack.release.yml +++ b/go/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 75963a0708e..65c84860754 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 0.5.3-dev +version: 0.5.3 groups: - go - queries diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md index 53fb1470bb9..4b72014d78e 100644 --- a/java/ql/lib/CHANGELOG.md +++ b/java/ql/lib/CHANGELOG.md @@ -1,3 +1,61 @@ +## 0.6.3 + +### New Features + +* Kotlin versions up to 1.9.0 are now supported. + +### Minor Analysis Improvements + +* Added flow through the block arguments of `kotlin.io.use` and `kotlin.with`. +* Added models for the following packages: + + * com.alibaba.druid.sql + * com.fasterxml.jackson.databind + * com.jcraft.jsch + * io.netty.handler.ssl + * okhttp3 + * org.antlr.runtime + * org.fusesource.leveldbjni + * org.influxdb + * org.springframework.core.io + * org.yaml.snakeyaml +* Deleted the deprecated `getRHS` predicate from the `LValue` class, use `getRhs` instead. +* Deleted the deprecated `getCFGNode` predicate from the `SsaVariable` class, use `getCfgNode` instead. +* Deleted many deprecated predicates and classes with uppercase `XML`, `JSON`, `URL`, `API`, etc. in their names. Use the PascalCased versions instead. +* Added models for the following packages: + + * java.lang + * java.nio.file +* Added dataflow models for the Gson deserialization library. +* Added models for the following packages: + + * okhttp3 +* Added more dataflow models for the Play Framework. +Modified the models related to `java.nio.file.Files.copy` so that generic `[Input|Output]Stream` arguments are not considered file-related sinks. +* Dataflow analysis has a new flow step through constructors of transitive subtypes of `java.io.InputStream` that wrap an underlying data source. Previously, the step only existed for direct subtypes of `java.io.InputStream`. +* Path creation sinks modeled in `PathCreation.qll` have been added to the models-as-data sink kind `path-injection`. +* Updated the regular expression in the `HostnameSanitizer` sanitizer in the `semmle.code.java.security.RequestForgery` library to better detect strings prefixed with a hostname. +* Changed the `android-widget` Java source kind to `remote`. Any custom data extensions that use the `android-widget` source kind will need to be updated accordingly in order to continue working. +* Updated the following Java sink kind names. Any custom data extensions will need to be updated accordingly in order to continue working. + * `sql` to `sql-injection` + * `url-redirect` to `url-redirection` + * `xpath` to `xpath-injection` + * `ssti` to `template-injection` + * `logging` to `log-injection` + * `groovy` to `groovy-injection` + * `jexl` to `jexl-injection` + * `mvel` to `mvel-injection` + * `xslt` to `xslt-injection` + * `ldap` to `ldap-injection` + * `pending-intent-sent` to `pending-intents` + * `intent-start` to `intent-redirection` + * `set-hostname-verifier` to `hostname-verification` + * `header-splitting` to `response-splitting` + * `xss` to `html-injection` and `js-injection` + * `write-file` to `file-system-store` + * `create-file` and `read-file` to `path-injection` + * `open-url` and `jdbc-url` to `request-forgery` + ## 0.6.2 ### Minor Analysis Improvements diff --git a/java/ql/lib/change-notes/2023-05-05-java-sink-kind-revamp.md b/java/ql/lib/change-notes/2023-05-05-java-sink-kind-revamp.md deleted file mode 100644 index ef54f491051..00000000000 --- a/java/ql/lib/change-notes/2023-05-05-java-sink-kind-revamp.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -category: minorAnalysis ---- -* Updated the following Java sink kind names. Any custom data extensions will need to be updated accordingly in order to continue working. - * `sql` to `sql-injection` - * `url-redirect` to `url-redirection` - * `xpath` to `xpath-injection` - * `ssti` to `template-injection` - * `logging` to `log-injection` - * `groovy` to `groovy-injection` - * `jexl` to `jexl-injection` - * `mvel` to `mvel-injection` - * `xslt` to `xslt-injection` - * `ldap` to `ldap-injection` - * `pending-intent-sent` to `pending-intents` - * `intent-start` to `intent-redirection` - * `set-hostname-verifier` to `hostname-verification` - * `header-splitting` to `response-splitting` - * `xss` to `html-injection` and `js-injection` - * `write-file` to `file-system-store` - * `create-file` and `read-file` to `path-injection` - * `open-url` and `jdbc-url` to `request-forgery` diff --git a/java/ql/lib/change-notes/2023-05-12-androidwidget-source-kind-to-remote.md b/java/ql/lib/change-notes/2023-05-12-androidwidget-source-kind-to-remote.md deleted file mode 100644 index 7a2714a6527..00000000000 --- a/java/ql/lib/change-notes/2023-05-12-androidwidget-source-kind-to-remote.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Changed the `android-widget` Java source kind to `remote`. Any custom data extensions that use the `android-widget` source kind will need to be updated accordingly in order to continue working. diff --git a/java/ql/lib/change-notes/2023-05-17-change-hostnamesanitizingprefix-regex.md b/java/ql/lib/change-notes/2023-05-17-change-hostnamesanitizingprefix-regex.md deleted file mode 100644 index 8d81c97d9e3..00000000000 --- a/java/ql/lib/change-notes/2023-05-17-change-hostnamesanitizingprefix-regex.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* Updated the regular expression in the `HostnameSanitizer` sanitizer in the `semmle.code.java.security.RequestForgery` library to better detect strings prefixed with a hostname. - diff --git a/java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md b/java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md deleted file mode 100644 index ae5cd306c2b..00000000000 --- a/java/ql/lib/change-notes/2023-05-19-path-injection-sinks-mad.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Path creation sinks modeled in `PathCreation.qll` have been added to the models-as-data sink kind `path-injection`. diff --git a/java/ql/lib/change-notes/2023-05-22-inputstreamwrapper-transitive.md b/java/ql/lib/change-notes/2023-05-22-inputstreamwrapper-transitive.md deleted file mode 100644 index bba77d98d89..00000000000 --- a/java/ql/lib/change-notes/2023-05-22-inputstreamwrapper-transitive.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Dataflow analysis has a new flow step through constructors of transitive subtypes of `java.io.InputStream` that wrap an underlying data source. Previously, the step only existed for direct subtypes of `java.io.InputStream`. diff --git a/java/ql/lib/change-notes/2023-05-23-java-nio-file-files-copy-models-tweak.md b/java/ql/lib/change-notes/2023-05-23-java-nio-file-files-copy-models-tweak.md deleted file mode 100644 index 85fc9b89197..00000000000 --- a/java/ql/lib/change-notes/2023-05-23-java-nio-file-files-copy-models-tweak.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -Modified the models related to `java.nio.file.Files.copy` so that generic `[Input|Output]Stream` arguments are not considered file-related sinks. diff --git a/java/ql/lib/change-notes/2023-05-24-kotlin-1.9.0.md b/java/ql/lib/change-notes/2023-05-24-kotlin-1.9.0.md deleted file mode 100644 index f3647cc5488..00000000000 --- a/java/ql/lib/change-notes/2023-05-24-kotlin-1.9.0.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: feature ---- -* Kotlin versions up to 1.9.0 are now supported. diff --git a/java/ql/lib/change-notes/2023-05-26-play-framework-models.md b/java/ql/lib/change-notes/2023-05-26-play-framework-models.md deleted file mode 100644 index 69db10413eb..00000000000 --- a/java/ql/lib/change-notes/2023-05-26-play-framework-models.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added more dataflow models for the Play Framework. diff --git a/java/ql/lib/change-notes/2023-05-30-gson-models.md b/java/ql/lib/change-notes/2023-05-30-gson-models.md deleted file mode 100644 index 306d797ff1a..00000000000 --- a/java/ql/lib/change-notes/2023-05-30-gson-models.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added dataflow models for the Gson deserialization library. diff --git a/java/ql/lib/change-notes/2023-05-30-new-models.md b/java/ql/lib/change-notes/2023-05-30-new-models.md deleted file mode 100644 index 24e7563d727..00000000000 --- a/java/ql/lib/change-notes/2023-05-30-new-models.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: minorAnalysis ---- -* Added models for the following packages: - - * okhttp3 diff --git a/java/ql/lib/change-notes/2023-06-01-new-models.md b/java/ql/lib/change-notes/2023-06-01-new-models.md deleted file mode 100644 index d05b3d4d59d..00000000000 --- a/java/ql/lib/change-notes/2023-06-01-new-models.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -category: minorAnalysis ---- -* Added models for the following packages: - - * java.lang - * java.nio.file diff --git a/java/ql/lib/change-notes/2023-06-02-delete-deps.md b/java/ql/lib/change-notes/2023-06-02-delete-deps.md deleted file mode 100644 index 01b2fd5a457..00000000000 --- a/java/ql/lib/change-notes/2023-06-02-delete-deps.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: minorAnalysis ---- -* Deleted the deprecated `getRHS` predicate from the `LValue` class, use `getRhs` instead. -* Deleted the deprecated `getCFGNode` predicate from the `SsaVariable` class, use `getCfgNode` instead. -* Deleted many deprecated predicates and classes with uppercase `XML`, `JSON`, `URL`, `API`, etc. in their names. Use the PascalCased versions instead. \ No newline at end of file diff --git a/java/ql/lib/change-notes/2023-06-06-kotlin-use-with-flow.md b/java/ql/lib/change-notes/2023-06-06-kotlin-use-with-flow.md deleted file mode 100644 index b21f31aae5f..00000000000 --- a/java/ql/lib/change-notes/2023-06-06-kotlin-use-with-flow.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added flow through the block arguments of `kotlin.io.use` and `kotlin.with`. diff --git a/java/ql/lib/change-notes/2023-06-06-new-models.md b/java/ql/lib/change-notes/2023-06-06-new-models.md deleted file mode 100644 index cbb80968749..00000000000 --- a/java/ql/lib/change-notes/2023-06-06-new-models.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -category: minorAnalysis ---- -* Added models for the following packages: - - * com.alibaba.druid.sql - * com.fasterxml.jackson.databind - * com.jcraft.jsch - * io.netty.handler.ssl - * okhttp3 - * org.antlr.runtime - * org.fusesource.leveldbjni - * org.influxdb - * org.springframework.core.io - * org.yaml.snakeyaml diff --git a/java/ql/lib/change-notes/released/0.6.3.md b/java/ql/lib/change-notes/released/0.6.3.md new file mode 100644 index 00000000000..b5b7e7f9556 --- /dev/null +++ b/java/ql/lib/change-notes/released/0.6.3.md @@ -0,0 +1,57 @@ +## 0.6.3 + +### New Features + +* Kotlin versions up to 1.9.0 are now supported. + +### Minor Analysis Improvements + +* Added flow through the block arguments of `kotlin.io.use` and `kotlin.with`. +* Added models for the following packages: + + * com.alibaba.druid.sql + * com.fasterxml.jackson.databind + * com.jcraft.jsch + * io.netty.handler.ssl + * okhttp3 + * org.antlr.runtime + * org.fusesource.leveldbjni + * org.influxdb + * org.springframework.core.io + * org.yaml.snakeyaml +* Deleted the deprecated `getRHS` predicate from the `LValue` class, use `getRhs` instead. +* Deleted the deprecated `getCFGNode` predicate from the `SsaVariable` class, use `getCfgNode` instead. +* Deleted many deprecated predicates and classes with uppercase `XML`, `JSON`, `URL`, `API`, etc. in their names. Use the PascalCased versions instead. +* Added models for the following packages: + + * java.lang + * java.nio.file +* Added dataflow models for the Gson deserialization library. +* Added models for the following packages: + + * okhttp3 +* Added more dataflow models for the Play Framework. +Modified the models related to `java.nio.file.Files.copy` so that generic `[Input|Output]Stream` arguments are not considered file-related sinks. +* Dataflow analysis has a new flow step through constructors of transitive subtypes of `java.io.InputStream` that wrap an underlying data source. Previously, the step only existed for direct subtypes of `java.io.InputStream`. +* Path creation sinks modeled in `PathCreation.qll` have been added to the models-as-data sink kind `path-injection`. +* Updated the regular expression in the `HostnameSanitizer` sanitizer in the `semmle.code.java.security.RequestForgery` library to better detect strings prefixed with a hostname. +* Changed the `android-widget` Java source kind to `remote`. Any custom data extensions that use the `android-widget` source kind will need to be updated accordingly in order to continue working. +* Updated the following Java sink kind names. Any custom data extensions will need to be updated accordingly in order to continue working. + * `sql` to `sql-injection` + * `url-redirect` to `url-redirection` + * `xpath` to `xpath-injection` + * `ssti` to `template-injection` + * `logging` to `log-injection` + * `groovy` to `groovy-injection` + * `jexl` to `jexl-injection` + * `mvel` to `mvel-injection` + * `xslt` to `xslt-injection` + * `ldap` to `ldap-injection` + * `pending-intent-sent` to `pending-intents` + * `intent-start` to `intent-redirection` + * `set-hostname-verifier` to `hostname-verification` + * `header-splitting` to `response-splitting` + * `xss` to `html-injection` and `js-injection` + * `write-file` to `file-system-store` + * `create-file` and `read-file` to `path-injection` + * `open-url` and `jdbc-url` to `request-forgery` diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml index 5501a2a1cc5..b7dafe32c5d 100644 --- a/java/ql/lib/codeql-pack.release.yml +++ b/java/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.2 +lastReleaseVersion: 0.6.3 diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index ada2ac9e999..8a18f2bdabb 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 0.6.3-dev +version: 0.6.3 groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md index 1e7cebcfca1..4852323b9b8 100644 --- a/java/ql/src/CHANGELOG.md +++ b/java/ql/src/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.6.3 + +### Minor Analysis Improvements + +* The `java/summary/lines-of-code` query now only counts lines of Java code. The new `java/summary/lines-of-code-kotlin` counts lines of Kotlin code. + ## 0.6.2 ### Minor Analysis Improvements diff --git a/java/ql/src/change-notes/2023-06-05-lines-of-code.md b/java/ql/src/change-notes/released/0.6.3.md similarity index 77% rename from java/ql/src/change-notes/2023-06-05-lines-of-code.md rename to java/ql/src/change-notes/released/0.6.3.md index a96c891e506..96665727131 100644 --- a/java/ql/src/change-notes/2023-06-05-lines-of-code.md +++ b/java/ql/src/change-notes/released/0.6.3.md @@ -1,4 +1,5 @@ ---- -category: minorAnalysis ---- +## 0.6.3 + +### Minor Analysis Improvements + * The `java/summary/lines-of-code` query now only counts lines of Java code. The new `java/summary/lines-of-code-kotlin` counts lines of Kotlin code. diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml index 5501a2a1cc5..b7dafe32c5d 100644 --- a/java/ql/src/codeql-pack.release.yml +++ b/java/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.2 +lastReleaseVersion: 0.6.3 diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index 2da31e822ff..b52ce1fd59c 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 0.6.3-dev +version: 0.6.3 groups: - java - queries diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md index 3ac3bc23481..b4c69e3a2fd 100644 --- a/javascript/ql/lib/CHANGELOG.md +++ b/javascript/ql/lib/CHANGELOG.md @@ -1,3 +1,23 @@ +## 0.6.3 + +### Major Analysis Improvements + +* Added support for TypeScript 5.1. + +### Minor Analysis Improvements + +* Deleted many deprecated predicates and classes with uppercase `XML`, `JSON`, `URL`, `API`, etc. in their names. Use the PascalCased versions instead. +* Deleted the deprecated `localTaintStep` predicate from `DataFlow.qll`. +* Deleted the deprecated `stringStep`, and `localTaintStep` predicates from `TaintTracking.qll`. +* Deleted many modules that started with a lowercase letter. Use the versions that start with an uppercase letter instead. +* Deleted the deprecated `HtmlInjectionConfiguration` and `JQueryHtmlOrSelectorInjectionConfiguration` classes from `DomBasedXssQuery.qll`, use `Configuration` instead. +* Deleted the deprecated `DefiningIdentifier` class and the `Definitions.qll` file it was in. Use `SsaDefinition` instead. +* Deleted the deprecated `definitionReaches`, `localDefinitionReaches`, `getAPseudoDefinitionInput`, `nextDefAfter`, and `localDefinitionOverwrites` predicates from `DefUse.qll`. +* Updated the following JavaScript sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working. + * `command-line-injection` to `command-injection` + * `credentials[kind]` to `credentials-kind` +- Added a support of sub modules in `node_modules`. + ## 0.6.2 ### Minor Analysis Improvements diff --git a/javascript/ql/lib/change-notes/2023-04-19-typescript-5-1.md b/javascript/ql/lib/change-notes/2023-04-19-typescript-5-1.md deleted file mode 100644 index 7260bd3d389..00000000000 --- a/javascript/ql/lib/change-notes/2023-04-19-typescript-5-1.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: majorAnalysis ---- -* Added support for TypeScript 5.1. \ No newline at end of file diff --git a/javascript/ql/lib/change-notes/2023-04-30-npm-submodule.md b/javascript/ql/lib/change-notes/2023-04-30-npm-submodule.md deleted file mode 100644 index 5ef95cf7d58..00000000000 --- a/javascript/ql/lib/change-notes/2023-04-30-npm-submodule.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- - -- Added a support of sub modules in `node_modules`. diff --git a/javascript/ql/lib/change-notes/2023-05-12-update-js-sink-kinds.md b/javascript/ql/lib/change-notes/2023-05-12-update-js-sink-kinds.md deleted file mode 100644 index 9d215924623..00000000000 --- a/javascript/ql/lib/change-notes/2023-05-12-update-js-sink-kinds.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: minorAnalysis ---- -* Updated the following JavaScript sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working. - * `command-line-injection` to `command-injection` - * `credentials[kind]` to `credentials-kind` diff --git a/javascript/ql/lib/change-notes/2023-06-02-delete-deps.md b/javascript/ql/lib/change-notes/released/0.6.3.md similarity index 64% rename from javascript/ql/lib/change-notes/2023-06-02-delete-deps.md rename to javascript/ql/lib/change-notes/released/0.6.3.md index 9edbce9771e..0559c0fd746 100644 --- a/javascript/ql/lib/change-notes/2023-06-02-delete-deps.md +++ b/javascript/ql/lib/change-notes/released/0.6.3.md @@ -1,10 +1,19 @@ ---- -category: minorAnalysis ---- +## 0.6.3 + +### Major Analysis Improvements + +* Added support for TypeScript 5.1. + +### Minor Analysis Improvements + * Deleted many deprecated predicates and classes with uppercase `XML`, `JSON`, `URL`, `API`, etc. in their names. Use the PascalCased versions instead. * Deleted the deprecated `localTaintStep` predicate from `DataFlow.qll`. * Deleted the deprecated `stringStep`, and `localTaintStep` predicates from `TaintTracking.qll`. * Deleted many modules that started with a lowercase letter. Use the versions that start with an uppercase letter instead. * Deleted the deprecated `HtmlInjectionConfiguration` and `JQueryHtmlOrSelectorInjectionConfiguration` classes from `DomBasedXssQuery.qll`, use `Configuration` instead. * Deleted the deprecated `DefiningIdentifier` class and the `Definitions.qll` file it was in. Use `SsaDefinition` instead. -* Deleted the deprecated `definitionReaches`, `localDefinitionReaches`, `getAPseudoDefinitionInput`, `nextDefAfter`, and `localDefinitionOverwrites` predicates from `DefUse.qll`. \ No newline at end of file +* Deleted the deprecated `definitionReaches`, `localDefinitionReaches`, `getAPseudoDefinitionInput`, `nextDefAfter`, and `localDefinitionOverwrites` predicates from `DefUse.qll`. +* Updated the following JavaScript sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working. + * `command-line-injection` to `command-injection` + * `credentials[kind]` to `credentials-kind` +- Added a support of sub modules in `node_modules`. diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml index 5501a2a1cc5..b7dafe32c5d 100644 --- a/javascript/ql/lib/codeql-pack.release.yml +++ b/javascript/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.2 +lastReleaseVersion: 0.6.3 diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index 52962f549b0..bda9945c1c3 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 0.6.3-dev +version: 0.6.3 groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md index eb914577876..0194f6f1c4a 100644 --- a/javascript/ql/src/CHANGELOG.md +++ b/javascript/ql/src/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.6.3 + +### Minor Analysis Improvements + +* Fixed an issue where calls to a method named `search` would lead to false positive alerts related to regular expressions. + This happened when the call was incorrectly seen as a call to `String.prototype.search`, since this function converts its first argument + to a regular expression. The analysis is now more restrictive about when to treat `search` calls as regular expression sinks. + ## 0.6.2 ### Major Analysis Improvements diff --git a/javascript/ql/src/change-notes/2023-06-01-restrict-regex-search-function.md b/javascript/ql/src/change-notes/released/0.6.3.md similarity index 90% rename from javascript/ql/src/change-notes/2023-06-01-restrict-regex-search-function.md rename to javascript/ql/src/change-notes/released/0.6.3.md index a43aebff717..3b5d43026f8 100644 --- a/javascript/ql/src/change-notes/2023-06-01-restrict-regex-search-function.md +++ b/javascript/ql/src/change-notes/released/0.6.3.md @@ -1,6 +1,7 @@ ---- -category: minorAnalysis ---- +## 0.6.3 + +### Minor Analysis Improvements + * Fixed an issue where calls to a method named `search` would lead to false positive alerts related to regular expressions. This happened when the call was incorrectly seen as a call to `String.prototype.search`, since this function converts its first argument to a regular expression. The analysis is now more restrictive about when to treat `search` calls as regular expression sinks. diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml index 5501a2a1cc5..b7dafe32c5d 100644 --- a/javascript/ql/src/codeql-pack.release.yml +++ b/javascript/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.2 +lastReleaseVersion: 0.6.3 diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index 10e071e417c..6df72dd450f 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 0.6.3-dev +version: 0.6.3 groups: - javascript - queries diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md index 46787616efa..9571c393549 100644 --- a/misc/suite-helpers/CHANGELOG.md +++ b/misc/suite-helpers/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.3 + +No user-facing changes. + ## 0.5.2 No user-facing changes. diff --git a/misc/suite-helpers/change-notes/released/0.5.3.md b/misc/suite-helpers/change-notes/released/0.5.3.md new file mode 100644 index 00000000000..e97503053f0 --- /dev/null +++ b/misc/suite-helpers/change-notes/released/0.5.3.md @@ -0,0 +1,3 @@ +## 0.5.3 + +No user-facing changes. diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/misc/suite-helpers/codeql-pack.release.yml +++ b/misc/suite-helpers/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index b6fbcda7201..60af5875e10 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,3 +1,3 @@ name: codeql/suite-helpers -version: 0.5.3-dev +version: 0.5.3 groups: shared diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md index 91f53df486b..3bfc2ddf115 100644 --- a/python/ql/lib/CHANGELOG.md +++ b/python/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.3 + +No user-facing changes. + ## 0.9.2 ### Minor Analysis Improvements diff --git a/python/ql/lib/change-notes/released/0.9.3.md b/python/ql/lib/change-notes/released/0.9.3.md new file mode 100644 index 00000000000..1c859ebb6b3 --- /dev/null +++ b/python/ql/lib/change-notes/released/0.9.3.md @@ -0,0 +1,3 @@ +## 0.9.3 + +No user-facing changes. diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml index e1eda519435..7af7247cbb0 100644 --- a/python/ql/lib/codeql-pack.release.yml +++ b/python/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.9.2 +lastReleaseVersion: 0.9.3 diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index 9d4522d5f58..101ed2a7232 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 0.9.3-dev +version: 0.9.3 groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md index 712de670fdc..655914b4a32 100644 --- a/python/ql/src/CHANGELOG.md +++ b/python/ql/src/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.7.3 + +### Bug Fixes + +* The display name (`@name`) of the `py/unsafe-deserialization` query has been updated in favor of consistency with other languages. + ## 0.7.2 No user-facing changes. diff --git a/python/ql/src/change-notes/2023-06-02-unsafe-deserialization-name-update.md b/python/ql/src/change-notes/released/0.7.3.md similarity index 81% rename from python/ql/src/change-notes/2023-06-02-unsafe-deserialization-name-update.md rename to python/ql/src/change-notes/released/0.7.3.md index d786e9dc14d..2f9c3725fb0 100644 --- a/python/ql/src/change-notes/2023-06-02-unsafe-deserialization-name-update.md +++ b/python/ql/src/change-notes/released/0.7.3.md @@ -1,4 +1,5 @@ ---- -category: fix ---- -* The display name (`@name`) of the `py/unsafe-deserialization` query has been updated in favor of consistency with other languages. \ No newline at end of file +## 0.7.3 + +### Bug Fixes + +* The display name (`@name`) of the `py/unsafe-deserialization` query has been updated in favor of consistency with other languages. diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml index fee171e9685..a4ea9c8de17 100644 --- a/python/ql/src/codeql-pack.release.yml +++ b/python/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.7.2 +lastReleaseVersion: 0.7.3 diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index eb327c2e42e..3c274ee84a9 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 0.7.3-dev +version: 0.7.3 groups: - python - queries diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md index 65eba10cc10..5803375fd51 100644 --- a/ruby/ql/lib/CHANGELOG.md +++ b/ruby/ql/lib/CHANGELOG.md @@ -1,3 +1,15 @@ +## 0.6.3 + +### Minor Analysis Improvements + +* Deleted many deprecated predicates and classes with uppercase `URL`, `XSS`, etc. in their names. Use the PascalCased versions instead. +* Deleted the deprecated `getValueText` predicate from the `Expr`, `StringComponent`, and `ExprCfgNode` classes. Use `getConstantValue` instead. +* Deleted the deprecated `VariableReferencePattern` class, use `ReferencePattern` instead. +* Deleted all deprecated aliases in `StandardLibrary.qll`, use `codeql.ruby.frameworks.Core` and `codeql.ruby.frameworks.Stdlib` instead. +* Support for the `sequel` gem has been added. Method calls that execute queries against a database that may be vulnerable to injection attacks will now be recognized. +* Support for the `mysql2` gem has been added. Method calls that execute queries against an MySQL database that may be vulnerable to injection attacks will now be recognized. +* Support for the `pg` gem has been added. Method calls that execute queries against a PostgreSQL database that may be vulnerable to injection attacks will now be recognized. + ## 0.6.2 ### Minor Analysis Improvements diff --git a/ruby/ql/lib/change-notes/2023-05-06-mysql2.md b/ruby/ql/lib/change-notes/2023-05-06-mysql2.md deleted file mode 100644 index d8fa92dd394..00000000000 --- a/ruby/ql/lib/change-notes/2023-05-06-mysql2.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Support for the `mysql2` gem has been added. Method calls that execute queries against an MySQL database that may be vulnerable to injection attacks will now be recognized. \ No newline at end of file diff --git a/ruby/ql/lib/change-notes/2023-05-06-pg.md b/ruby/ql/lib/change-notes/2023-05-06-pg.md deleted file mode 100644 index 0e671ff9106..00000000000 --- a/ruby/ql/lib/change-notes/2023-05-06-pg.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Support for the `pg` gem has been added. Method calls that execute queries against a PostgreSQL database that may be vulnerable to injection attacks will now be recognized. \ No newline at end of file diff --git a/ruby/ql/lib/change-notes/2023-05-07-sequel.md b/ruby/ql/lib/change-notes/2023-05-07-sequel.md deleted file mode 100644 index 3688f28db56..00000000000 --- a/ruby/ql/lib/change-notes/2023-05-07-sequel.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Support for the `sequel` gem has been added. Method calls that execute queries against a database that may be vulnerable to injection attacks will now be recognized. diff --git a/ruby/ql/lib/change-notes/2023-06-02-delete-deps.md b/ruby/ql/lib/change-notes/2023-06-02-delete-deps.md deleted file mode 100644 index f4df20530dc..00000000000 --- a/ruby/ql/lib/change-notes/2023-06-02-delete-deps.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -category: minorAnalysis ---- -* Deleted many deprecated predicates and classes with uppercase `URL`, `XSS`, etc. in their names. Use the PascalCased versions instead. -* Deleted the deprecated `getValueText` predicate from the `Expr`, `StringComponent`, and `ExprCfgNode` classes. Use `getConstantValue` instead. -* Deleted the deprecated `VariableReferencePattern` class, use `ReferencePattern` instead. -* Deleted all deprecated aliases in `StandardLibrary.qll`, use `codeql.ruby.frameworks.Core` and `codeql.ruby.frameworks.Stdlib` instead. \ No newline at end of file diff --git a/ruby/ql/lib/change-notes/released/0.6.3.md b/ruby/ql/lib/change-notes/released/0.6.3.md new file mode 100644 index 00000000000..35121021e9a --- /dev/null +++ b/ruby/ql/lib/change-notes/released/0.6.3.md @@ -0,0 +1,11 @@ +## 0.6.3 + +### Minor Analysis Improvements + +* Deleted many deprecated predicates and classes with uppercase `URL`, `XSS`, etc. in their names. Use the PascalCased versions instead. +* Deleted the deprecated `getValueText` predicate from the `Expr`, `StringComponent`, and `ExprCfgNode` classes. Use `getConstantValue` instead. +* Deleted the deprecated `VariableReferencePattern` class, use `ReferencePattern` instead. +* Deleted all deprecated aliases in `StandardLibrary.qll`, use `codeql.ruby.frameworks.Core` and `codeql.ruby.frameworks.Stdlib` instead. +* Support for the `sequel` gem has been added. Method calls that execute queries against a database that may be vulnerable to injection attacks will now be recognized. +* Support for the `mysql2` gem has been added. Method calls that execute queries against an MySQL database that may be vulnerable to injection attacks will now be recognized. +* Support for the `pg` gem has been added. Method calls that execute queries against a PostgreSQL database that may be vulnerable to injection attacks will now be recognized. diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml index 5501a2a1cc5..b7dafe32c5d 100644 --- a/ruby/ql/lib/codeql-pack.release.yml +++ b/ruby/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.2 +lastReleaseVersion: 0.6.3 diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index bb01a5ff87d..2591c99f5cf 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 0.6.3-dev +version: 0.6.3 groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md index 7e2e0df8b38..8bc499539cb 100644 --- a/ruby/ql/src/CHANGELOG.md +++ b/ruby/ql/src/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.6.3 + +### Minor Analysis Improvements + +* Fixed a bug that would occur when an `initialize` method returns `self` or one of its parameters. + In such cases, the corresponding calls to `new` would be associated with an incorrect return type. + This could result in inaccurate call target resolution and cause false positive alerts. +* Fixed an issue where calls to `delete` or `assoc` with a constant-valued argument would be analyzed imprecisely, + as if the argument value was not a known constant. + ## 0.6.2 No user-facing changes. diff --git a/ruby/ql/src/change-notes/2023-05-24-delete-name-clash.md b/ruby/ql/src/change-notes/2023-05-24-delete-name-clash.md deleted file mode 100644 index 347a7b118db..00000000000 --- a/ruby/ql/src/change-notes/2023-05-24-delete-name-clash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* Fixed an issue where calls to `delete` or `assoc` with a constant-valued argument would be analyzed imprecisely, - as if the argument value was not a known constant. diff --git a/ruby/ql/src/change-notes/2023-05-26-super-and-flow-through.md b/ruby/ql/src/change-notes/released/0.6.3.md similarity index 57% rename from ruby/ql/src/change-notes/2023-05-26-super-and-flow-through.md rename to ruby/ql/src/change-notes/released/0.6.3.md index 7059c51f24e..53544eca039 100644 --- a/ruby/ql/src/change-notes/2023-05-26-super-and-flow-through.md +++ b/ruby/ql/src/change-notes/released/0.6.3.md @@ -1,6 +1,9 @@ ---- -category: minorAnalysis ---- +## 0.6.3 + +### Minor Analysis Improvements + * Fixed a bug that would occur when an `initialize` method returns `self` or one of its parameters. In such cases, the corresponding calls to `new` would be associated with an incorrect return type. This could result in inaccurate call target resolution and cause false positive alerts. +* Fixed an issue where calls to `delete` or `assoc` with a constant-valued argument would be analyzed imprecisely, + as if the argument value was not a known constant. diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml index 5501a2a1cc5..b7dafe32c5d 100644 --- a/ruby/ql/src/codeql-pack.release.yml +++ b/ruby/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.2 +lastReleaseVersion: 0.6.3 diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index 3bc462dc7ee..f98583c5f80 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 0.6.3-dev +version: 0.6.3 groups: - ruby - queries diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md index cc83ed1e68c..e45483b6d3c 100644 --- a/shared/regex/CHANGELOG.md +++ b/shared/regex/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.14 + +No user-facing changes. + ## 0.0.13 No user-facing changes. diff --git a/shared/regex/change-notes/released/0.0.14.md b/shared/regex/change-notes/released/0.0.14.md new file mode 100644 index 00000000000..63b4d50ca45 --- /dev/null +++ b/shared/regex/change-notes/released/0.0.14.md @@ -0,0 +1,3 @@ +## 0.0.14 + +No user-facing changes. diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml index 044e54e4f7e..ca29e45d0a6 100644 --- a/shared/regex/codeql-pack.release.yml +++ b/shared/regex/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.13 +lastReleaseVersion: 0.0.14 diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml index 86b105c881a..63d34ec6329 100644 --- a/shared/regex/qlpack.yml +++ b/shared/regex/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/regex -version: 0.0.14-dev +version: 0.0.14 groups: shared library: true dependencies: diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md index 5e42000c1d1..41f9216baff 100644 --- a/shared/ssa/CHANGELOG.md +++ b/shared/ssa/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.18 + +No user-facing changes. + ## 0.0.17 No user-facing changes. diff --git a/shared/ssa/change-notes/released/0.0.18.md b/shared/ssa/change-notes/released/0.0.18.md new file mode 100644 index 00000000000..86c60b8abe7 --- /dev/null +++ b/shared/ssa/change-notes/released/0.0.18.md @@ -0,0 +1,3 @@ +## 0.0.18 + +No user-facing changes. diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml index cbc3d3cd493..a0d2bc59d97 100644 --- a/shared/ssa/codeql-pack.release.yml +++ b/shared/ssa/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.17 +lastReleaseVersion: 0.0.18 diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index 55ebe316292..be427812ded 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ssa -version: 0.0.18-dev +version: 0.0.18 groups: shared library: true warnOnImplicitThis: true diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md index 02876619527..28a38e6333b 100644 --- a/shared/tutorial/CHANGELOG.md +++ b/shared/tutorial/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.11 + +No user-facing changes. + ## 0.0.10 No user-facing changes. diff --git a/shared/tutorial/change-notes/released/0.0.11.md b/shared/tutorial/change-notes/released/0.0.11.md new file mode 100644 index 00000000000..19a2a55bd68 --- /dev/null +++ b/shared/tutorial/change-notes/released/0.0.11.md @@ -0,0 +1,3 @@ +## 0.0.11 + +No user-facing changes. diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml index b740014e5ae..e679dc42092 100644 --- a/shared/tutorial/codeql-pack.release.yml +++ b/shared/tutorial/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.10 +lastReleaseVersion: 0.0.11 diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml index af7544c0ae9..9d655dcca3e 100644 --- a/shared/tutorial/qlpack.yml +++ b/shared/tutorial/qlpack.yml @@ -1,6 +1,6 @@ name: codeql/tutorial description: Library for the CodeQL detective tutorials, helping new users learn to write CodeQL queries. -version: 0.0.11-dev +version: 0.0.11 groups: shared library: true warnOnImplicitThis: true diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md index c8729dc39f8..e87bb476477 100644 --- a/shared/typetracking/CHANGELOG.md +++ b/shared/typetracking/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.11 + +No user-facing changes. + ## 0.0.10 No user-facing changes. diff --git a/shared/typetracking/change-notes/released/0.0.11.md b/shared/typetracking/change-notes/released/0.0.11.md new file mode 100644 index 00000000000..19a2a55bd68 --- /dev/null +++ b/shared/typetracking/change-notes/released/0.0.11.md @@ -0,0 +1,3 @@ +## 0.0.11 + +No user-facing changes. diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml index b740014e5ae..e679dc42092 100644 --- a/shared/typetracking/codeql-pack.release.yml +++ b/shared/typetracking/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.10 +lastReleaseVersion: 0.0.11 diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml index 10e32e39f99..ca6b6a9c76e 100644 --- a/shared/typetracking/qlpack.yml +++ b/shared/typetracking/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typetracking -version: 0.0.11-dev +version: 0.0.11 groups: shared library: true dependencies: diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md index 472d0ef41a5..9b3dcbace69 100644 --- a/shared/typos/CHANGELOG.md +++ b/shared/typos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.18 + +No user-facing changes. + ## 0.0.17 No user-facing changes. diff --git a/shared/typos/change-notes/released/0.0.18.md b/shared/typos/change-notes/released/0.0.18.md new file mode 100644 index 00000000000..86c60b8abe7 --- /dev/null +++ b/shared/typos/change-notes/released/0.0.18.md @@ -0,0 +1,3 @@ +## 0.0.18 + +No user-facing changes. diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml index cbc3d3cd493..a0d2bc59d97 100644 --- a/shared/typos/codeql-pack.release.yml +++ b/shared/typos/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.17 +lastReleaseVersion: 0.0.18 diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml index fa4fe52aace..b3796de8fa1 100644 --- a/shared/typos/qlpack.yml +++ b/shared/typos/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typos -version: 0.0.18-dev +version: 0.0.18 groups: shared library: true warnOnImplicitThis: true diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md index 99aa576343d..fe9befff25a 100644 --- a/shared/util/CHANGELOG.md +++ b/shared/util/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.11 + +No user-facing changes. + ## 0.0.10 No user-facing changes. diff --git a/shared/util/change-notes/released/0.0.11.md b/shared/util/change-notes/released/0.0.11.md new file mode 100644 index 00000000000..19a2a55bd68 --- /dev/null +++ b/shared/util/change-notes/released/0.0.11.md @@ -0,0 +1,3 @@ +## 0.0.11 + +No user-facing changes. diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml index b740014e5ae..e679dc42092 100644 --- a/shared/util/codeql-pack.release.yml +++ b/shared/util/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.10 +lastReleaseVersion: 0.0.11 diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index c044709ceee..f48343df59f 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/util -version: 0.0.11-dev +version: 0.0.11 groups: shared library: true dependencies: diff --git a/shared/yaml/CHANGELOG.md b/shared/yaml/CHANGELOG.md index 9119d5fc839..390989ba76a 100644 --- a/shared/yaml/CHANGELOG.md +++ b/shared/yaml/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.3 + +No user-facing changes. + ## 0.0.2 No user-facing changes. diff --git a/shared/yaml/change-notes/released/0.0.3.md b/shared/yaml/change-notes/released/0.0.3.md new file mode 100644 index 00000000000..af7864fc7d5 --- /dev/null +++ b/shared/yaml/change-notes/released/0.0.3.md @@ -0,0 +1,3 @@ +## 0.0.3 + +No user-facing changes. diff --git a/shared/yaml/codeql-pack.release.yml b/shared/yaml/codeql-pack.release.yml index 55dc06fbd76..a24b693d1e7 100644 --- a/shared/yaml/codeql-pack.release.yml +++ b/shared/yaml/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.2 +lastReleaseVersion: 0.0.3 diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml index 6b9f33c9125..e379f9bd9e1 100644 --- a/shared/yaml/qlpack.yml +++ b/shared/yaml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/yaml -version: 0.0.3-dev +version: 0.0.3 groups: shared library: true warnOnImplicitThis: true From bff11c3d2352812aa68ce3068c04cd424ae637e0 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <93738568+jketema@users.noreply.github.com> Date: Thu, 8 Jun 2023 22:33:50 +0200 Subject: [PATCH 059/364] Apply suggestions from code review --- java/ql/lib/CHANGELOG.md | 2 +- java/ql/lib/change-notes/released/0.6.3.md | 2 +- javascript/ql/lib/CHANGELOG.md | 2 +- javascript/ql/lib/change-notes/released/0.6.3.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md index 4b72014d78e..1056cefb86a 100644 --- a/java/ql/lib/CHANGELOG.md +++ b/java/ql/lib/CHANGELOG.md @@ -31,7 +31,7 @@ * okhttp3 * Added more dataflow models for the Play Framework. -Modified the models related to `java.nio.file.Files.copy` so that generic `[Input|Output]Stream` arguments are not considered file-related sinks. +* Modified the models related to `java.nio.file.Files.copy` so that generic `[Input|Output]Stream` arguments are not considered file-related sinks. * Dataflow analysis has a new flow step through constructors of transitive subtypes of `java.io.InputStream` that wrap an underlying data source. Previously, the step only existed for direct subtypes of `java.io.InputStream`. * Path creation sinks modeled in `PathCreation.qll` have been added to the models-as-data sink kind `path-injection`. * Updated the regular expression in the `HostnameSanitizer` sanitizer in the `semmle.code.java.security.RequestForgery` library to better detect strings prefixed with a hostname. diff --git a/java/ql/lib/change-notes/released/0.6.3.md b/java/ql/lib/change-notes/released/0.6.3.md index b5b7e7f9556..05c95272941 100644 --- a/java/ql/lib/change-notes/released/0.6.3.md +++ b/java/ql/lib/change-notes/released/0.6.3.md @@ -31,7 +31,7 @@ * okhttp3 * Added more dataflow models for the Play Framework. -Modified the models related to `java.nio.file.Files.copy` so that generic `[Input|Output]Stream` arguments are not considered file-related sinks. +* Modified the models related to `java.nio.file.Files.copy` so that generic `[Input|Output]Stream` arguments are not considered file-related sinks. * Dataflow analysis has a new flow step through constructors of transitive subtypes of `java.io.InputStream` that wrap an underlying data source. Previously, the step only existed for direct subtypes of `java.io.InputStream`. * Path creation sinks modeled in `PathCreation.qll` have been added to the models-as-data sink kind `path-injection`. * Updated the regular expression in the `HostnameSanitizer` sanitizer in the `semmle.code.java.security.RequestForgery` library to better detect strings prefixed with a hostname. diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md index b4c69e3a2fd..47c4130c3af 100644 --- a/javascript/ql/lib/CHANGELOG.md +++ b/javascript/ql/lib/CHANGELOG.md @@ -16,7 +16,7 @@ * Updated the following JavaScript sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working. * `command-line-injection` to `command-injection` * `credentials[kind]` to `credentials-kind` -- Added a support of sub modules in `node_modules`. +* Added a support of sub modules in `node_modules`. ## 0.6.2 diff --git a/javascript/ql/lib/change-notes/released/0.6.3.md b/javascript/ql/lib/change-notes/released/0.6.3.md index 0559c0fd746..c87e2deb626 100644 --- a/javascript/ql/lib/change-notes/released/0.6.3.md +++ b/javascript/ql/lib/change-notes/released/0.6.3.md @@ -16,4 +16,4 @@ * Updated the following JavaScript sink kind names. Any custom data extensions that use these sink kinds will need to be updated accordingly in order to continue working. * `command-line-injection` to `command-injection` * `credentials[kind]` to `credentials-kind` -- Added a support of sub modules in `node_modules`. +* Added a support of sub modules in `node_modules`. From da58b2afc8323a2e69038a661cc8515b91b1988d Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Thu, 8 Jun 2023 20:05:27 -0400 Subject: [PATCH 060/364] Shared: move shared file to 'shared' folder and add parameterized module for 'getInvalidModelKind' --- config/identical-files.json | 9 - csharp/ql/lib/qlpack.yml | 1 + .../code/csharp/dataflow/ExternalFlow.qll | 44 ++--- .../internal/SharedModelValidation.qll | 143 -------------- go/ql/lib/qlpack.yml | 1 + go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 39 ++-- .../internal/SharedModelValidation.qll | 143 -------------- java/ql/lib/qlpack.yml | 1 + .../code/java/dataflow/ExternalFlow.qll | 44 ++--- .../internal/SharedModelValidation.qll | 143 -------------- javascript/ql/lib/qlpack.yml | 1 + .../data/internal/ApiGraphModels.qll | 39 ++-- .../data/internal/SharedModelValidation.qll | 143 -------------- python/ql/lib/qlpack.yml | 1 + .../data/internal/ApiGraphModels.qll | 39 ++-- .../data/internal/SharedModelValidation.qll | 143 -------------- .../data/internal/ApiGraphModels.qll | 39 ++-- .../data/internal/SharedModelValidation.qll | 143 -------------- ruby/ql/lib/qlpack.yml | 1 + shared/mad/codeql-pack.lock.yml | 4 + shared/mad/codeql-pack.release.yml | 2 + shared/mad/codeql/mad/ModelValidation.qll | 177 ++++++++++++++++++ shared/mad/qlpack.yml | 6 + .../codeql/swift/dataflow/ExternalFlow.qll | 40 ++-- .../internal/SharedModelValidation.qll | 143 -------------- swift/ql/lib/qlpack.yml | 1 + 26 files changed, 308 insertions(+), 1182 deletions(-) delete mode 100644 csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll delete mode 100644 go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll delete mode 100644 java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll delete mode 100644 javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll delete mode 100644 python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll delete mode 100644 ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll create mode 100644 shared/mad/codeql-pack.lock.yml create mode 100644 shared/mad/codeql-pack.release.yml create mode 100644 shared/mad/codeql/mad/ModelValidation.qll create mode 100644 shared/mad/qlpack.yml delete mode 100644 swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll diff --git a/config/identical-files.json b/config/identical-files.json index 52adf242dda..3c16c953129 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -598,14 +598,5 @@ "EncryptionKeySizes Python/Java": [ "python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll", "java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll" - ], - "SharedModelValidation Java/C#/Go/JS/Python/Ruby/Swift": [ - "java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll", - "go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll", - "swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll", - "javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll", - "python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll", - "ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll" ] } diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 17e00fa022c..093187eb865 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ extractor: csharp library: true upgrades: upgrades dependencies: + codeql/mad: ${workspace} codeql/ssa: ${workspace} codeql/tutorial: ${workspace} codeql/util: ${workspace} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 28c681e26df..ae1c928b92c 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -95,7 +95,7 @@ private import internal.DataFlowPublic private import internal.FlowSummaryImpl::Public private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImplSpecific -private import internal.SharedModelValidation +private import codeql.mad.ModelValidation as SharedModelVal /** Holds if a source model exists for the given parameters. */ predicate sourceModel = Extensions::sourceModel/9; @@ -205,32 +205,20 @@ module ModelValidation { ) } - /** Gets an error message relating to an invalid kind in a model. */ - private string getInvalidModelKind() { - exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSummaryKind and - result = "Invalid kind \"" + kind + "\" in summary model." - ) - or - exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSinkKind and - msg = "Invalid kind \"" + kind + "\" in sink model." and - // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. - if kind instanceof OutdatedSinkKind - then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() - else result = msg - ) - or - exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSourceKind and - result = "Invalid kind \"" + kind + "\" in source model." - ) - or - exists(string kind | neutralModel(_, _, _, _, kind, _) | - not kind instanceof ValidNeutralKind and - result = "Invalid kind \"" + kind + "\" in neutral model." - ) - } + /** Holds if a summary model exists for the given `kind`. */ + private predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } + + /** Holds if a sink model exists for the given `kind`. */ + private predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } + + /** Holds if a source model exists for the given `kind`. */ + private predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } + + /** Holds if a neutral model exists for the given `kind`. */ + private predicate neutralKind(string kind) { neutralModel(_, _, _, _, kind, _) } + + private module KindVal = + SharedModelVal::KindValidation; private string getInvalidModelSignature() { exists( @@ -273,7 +261,7 @@ module ModelValidation { msg = [ getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(), - getInvalidModelKind() + KindVal::getInvalidModelKind() ] } } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll deleted file mode 100644 index c322bc62029..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SharedModelValidation.qll +++ /dev/null @@ -1,143 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides classes and predicates related to validating models-as-data rows. - * Such that we can share this logic across our CodeQL analysis of different languages. - */ - -/** A valid models-as-data sink kind. */ -class ValidSinkKind extends string { - bindingset[this] - ValidSinkKind() { - this = - [ - // shared - "code-injection", "command-injection", "file-content-store", "html-injection", - "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", - "sql-injection", "url-redirection", - // Java-only currently, but may be shared in the future - "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", - "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", - "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", - "template-injection", "xpath-injection", "xslt-injection", - // JavaScript-only currently, but may be shared in the future - "mongodb.sink", "nosql-injection", "unsafe-deserialization", - // Swift-only currently, but may be shared in the future - "database-store", "format-string", "hash-iteration-count", "predicate-injection", - "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" - ] - or - this.matches([ - // shared - "encryption-%", "qltest%", "test-%", - // Java-only currently, but may be shared in the future - "regex-use%", - // JavaScript-only currently, but may be shared in the future - "credentials-%", - // Swift-only currently, but may be shared in the future - "%string-%length", "weak-hash-input-%" - ]) - } -} - -/** An outdated models-as-data sink kind. */ -class OutdatedSinkKind extends string { - OutdatedSinkKind() { - this = - [ - "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", - "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", - "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote", "uncontrolled-format-string", "js-eval" - ] - } - - /** Gets a replacement kind for an outdated sink kind. */ - private string replacementKind() { - this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and - result = this + "-injection" - or - this = "js-eval" and result = "code-injection" - or - this = "url-redirect" and result = "url-redirection" - or - this = "ssti" and result = "template-injection" - or - this = "logging" and result = "log-injection" - or - this = "pending-intent-sent" and result = "pending-intents" - or - this = "intent-start" and result = "intent-redirection" - or - this = "set-hostname-verifier" and result = "hostname-verification" - or - this = "header-splitting" and result = "response-splitting" - or - this = "xss" and result = "html-injection\" or \"js-injection" - or - this = ["write-file", "remote"] and result = "file-content-store" - or - this = ["create-file", "read-file"] and result = "path-injection" - or - this = ["open-url", "jdbc-url"] and result = "request-forgery" - or - this = "command-line-injection" and result = "command-injection" - or - this = "uncontrolled-format-string" and result = "format-string" - } - - /** Gets an error message for an outdated sink kind. */ - string outdatedMessage() { - result = - "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." - } -} - -/** A valid models-as-data source kind. */ -class ValidSourceKind extends string { - bindingset[this] - ValidSourceKind() { - this = - [ - // shared - "local", "remote", - // Java - "android-external-storage-dir", "contentprovider", - // C# - "file", "file-write", - // JavaScript - "database-access-result", "remote-flow" - ] - or - this.matches([ - // shared - "qltest%", "test-%", - // Swift - "%string-%length" - ]) - } -} - -/** A valid models-as-data summary kind. */ -class ValidSummaryKind extends string { - ValidSummaryKind() { - this = - [ - // shared - "taint", "value", - // JavaScript - "type" - ] - } -} - -/** A valid models-as-data neutral kind. */ -class ValidNeutralKind extends string { - ValidNeutralKind() { - this = - [ - // Java/C# currently - "sink", "source", "summary" - ] - } -} diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index 287c27187e3..271e9e13385 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ extractor: go library: true upgrades: upgrades dependencies: + codeql/mad: ${workspace} codeql/tutorial: ${workspace} codeql/util: ${workspace} dataExtensions: diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 9dbb826c35a..448196fb1a0 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -68,7 +68,7 @@ private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImplSpecific private import internal.AccessPathSyntax private import FlowSummary -private import internal.SharedModelValidation +private import codeql.mad.ModelValidation as SharedModelVal /** * A module importing the frameworks that provide external flow data, @@ -189,27 +189,20 @@ module ModelValidation { ) } - /** Gets an error message relating to an invalid kind in a model. */ - private string getInvalidModelKind() { - exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSummaryKind and - result = "Invalid kind \"" + kind + "\" in summary model." - ) - or - exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSinkKind and - msg = "Invalid kind \"" + kind + "\" in sink model." and - // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. - if kind instanceof OutdatedSinkKind - then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() - else result = msg - ) - or - exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSourceKind and - result = "Invalid kind \"" + kind + "\" in source model." - ) - } + /** Holds if a summary model exists for the given `kind`. */ + private predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } + + /** Holds if a sink model exists for the given `kind`. */ + private predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } + + /** Holds if a source model exists for the given `kind`. */ + private predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } + + /** Holds if a neutral model exists for the given `kind`. */ + private predicate neutralKind(string kind) { none() } + + private module KindVal = + SharedModelVal::KindValidation; private string getInvalidModelSignature() { exists( @@ -247,7 +240,7 @@ module ModelValidation { msg = [ getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(), - getInvalidModelKind() + KindVal::getInvalidModelKind() ] } } diff --git a/go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll b/go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll deleted file mode 100644 index c322bc62029..00000000000 --- a/go/ql/lib/semmle/go/dataflow/internal/SharedModelValidation.qll +++ /dev/null @@ -1,143 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides classes and predicates related to validating models-as-data rows. - * Such that we can share this logic across our CodeQL analysis of different languages. - */ - -/** A valid models-as-data sink kind. */ -class ValidSinkKind extends string { - bindingset[this] - ValidSinkKind() { - this = - [ - // shared - "code-injection", "command-injection", "file-content-store", "html-injection", - "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", - "sql-injection", "url-redirection", - // Java-only currently, but may be shared in the future - "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", - "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", - "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", - "template-injection", "xpath-injection", "xslt-injection", - // JavaScript-only currently, but may be shared in the future - "mongodb.sink", "nosql-injection", "unsafe-deserialization", - // Swift-only currently, but may be shared in the future - "database-store", "format-string", "hash-iteration-count", "predicate-injection", - "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" - ] - or - this.matches([ - // shared - "encryption-%", "qltest%", "test-%", - // Java-only currently, but may be shared in the future - "regex-use%", - // JavaScript-only currently, but may be shared in the future - "credentials-%", - // Swift-only currently, but may be shared in the future - "%string-%length", "weak-hash-input-%" - ]) - } -} - -/** An outdated models-as-data sink kind. */ -class OutdatedSinkKind extends string { - OutdatedSinkKind() { - this = - [ - "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", - "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", - "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote", "uncontrolled-format-string", "js-eval" - ] - } - - /** Gets a replacement kind for an outdated sink kind. */ - private string replacementKind() { - this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and - result = this + "-injection" - or - this = "js-eval" and result = "code-injection" - or - this = "url-redirect" and result = "url-redirection" - or - this = "ssti" and result = "template-injection" - or - this = "logging" and result = "log-injection" - or - this = "pending-intent-sent" and result = "pending-intents" - or - this = "intent-start" and result = "intent-redirection" - or - this = "set-hostname-verifier" and result = "hostname-verification" - or - this = "header-splitting" and result = "response-splitting" - or - this = "xss" and result = "html-injection\" or \"js-injection" - or - this = ["write-file", "remote"] and result = "file-content-store" - or - this = ["create-file", "read-file"] and result = "path-injection" - or - this = ["open-url", "jdbc-url"] and result = "request-forgery" - or - this = "command-line-injection" and result = "command-injection" - or - this = "uncontrolled-format-string" and result = "format-string" - } - - /** Gets an error message for an outdated sink kind. */ - string outdatedMessage() { - result = - "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." - } -} - -/** A valid models-as-data source kind. */ -class ValidSourceKind extends string { - bindingset[this] - ValidSourceKind() { - this = - [ - // shared - "local", "remote", - // Java - "android-external-storage-dir", "contentprovider", - // C# - "file", "file-write", - // JavaScript - "database-access-result", "remote-flow" - ] - or - this.matches([ - // shared - "qltest%", "test-%", - // Swift - "%string-%length" - ]) - } -} - -/** A valid models-as-data summary kind. */ -class ValidSummaryKind extends string { - ValidSummaryKind() { - this = - [ - // shared - "taint", "value", - // JavaScript - "type" - ] - } -} - -/** A valid models-as-data neutral kind. */ -class ValidNeutralKind extends string { - ValidNeutralKind() { - this = - [ - // Java/C# currently - "sink", "source", "summary" - ] - } -} diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index ada2ac9e999..c917caf0641 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ extractor: java library: true upgrades: upgrades dependencies: + codeql/mad: ${workspace} codeql/regex: ${workspace} codeql/tutorial: ${workspace} codeql/typetracking: ${workspace} diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 0a838e2fdd9..b0a5b702fa0 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -87,7 +87,7 @@ private import internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific private import internal.AccessPathSyntax private import ExternalFlowExtensions as Extensions private import FlowSummary -private import internal.SharedModelValidation +private import codeql.mad.ModelValidation as SharedModelVal /** * A class for activating additional model rows. @@ -266,32 +266,20 @@ module ModelValidation { ) } - /** Gets an error message relating to an invalid kind in a model. */ - private string getInvalidModelKind() { - exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSummaryKind and - result = "Invalid kind \"" + kind + "\" in summary model." - ) - or - exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSinkKind and - msg = "Invalid kind \"" + kind + "\" in sink model." and - // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. - if kind instanceof OutdatedSinkKind - then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() - else result = msg - ) - or - exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSourceKind and - result = "Invalid kind \"" + kind + "\" in source model." - ) - or - exists(string kind | neutralModel(_, _, _, _, kind, _) | - not kind instanceof ValidNeutralKind and - result = "Invalid kind \"" + kind + "\" in neutral model." - ) - } + /** Holds if a summary model exists for the given `kind`. */ + private predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } + + /** Holds if a sink model exists for the given `kind`. */ + private predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } + + /** Holds if a source model exists for the given `kind`. */ + private predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } + + /** Holds if a neutral model exists for the given `kind`. */ + private predicate neutralKind(string kind) { neutralModel(_, _, _, _, kind, _) } + + private module KindVal = + SharedModelVal::KindValidation; private string getInvalidModelSignature() { exists( @@ -334,7 +322,7 @@ module ModelValidation { msg = [ getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(), - getInvalidModelKind() + KindVal::getInvalidModelKind() ] } } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll b/java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll deleted file mode 100644 index c322bc62029..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/SharedModelValidation.qll +++ /dev/null @@ -1,143 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides classes and predicates related to validating models-as-data rows. - * Such that we can share this logic across our CodeQL analysis of different languages. - */ - -/** A valid models-as-data sink kind. */ -class ValidSinkKind extends string { - bindingset[this] - ValidSinkKind() { - this = - [ - // shared - "code-injection", "command-injection", "file-content-store", "html-injection", - "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", - "sql-injection", "url-redirection", - // Java-only currently, but may be shared in the future - "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", - "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", - "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", - "template-injection", "xpath-injection", "xslt-injection", - // JavaScript-only currently, but may be shared in the future - "mongodb.sink", "nosql-injection", "unsafe-deserialization", - // Swift-only currently, but may be shared in the future - "database-store", "format-string", "hash-iteration-count", "predicate-injection", - "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" - ] - or - this.matches([ - // shared - "encryption-%", "qltest%", "test-%", - // Java-only currently, but may be shared in the future - "regex-use%", - // JavaScript-only currently, but may be shared in the future - "credentials-%", - // Swift-only currently, but may be shared in the future - "%string-%length", "weak-hash-input-%" - ]) - } -} - -/** An outdated models-as-data sink kind. */ -class OutdatedSinkKind extends string { - OutdatedSinkKind() { - this = - [ - "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", - "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", - "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote", "uncontrolled-format-string", "js-eval" - ] - } - - /** Gets a replacement kind for an outdated sink kind. */ - private string replacementKind() { - this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and - result = this + "-injection" - or - this = "js-eval" and result = "code-injection" - or - this = "url-redirect" and result = "url-redirection" - or - this = "ssti" and result = "template-injection" - or - this = "logging" and result = "log-injection" - or - this = "pending-intent-sent" and result = "pending-intents" - or - this = "intent-start" and result = "intent-redirection" - or - this = "set-hostname-verifier" and result = "hostname-verification" - or - this = "header-splitting" and result = "response-splitting" - or - this = "xss" and result = "html-injection\" or \"js-injection" - or - this = ["write-file", "remote"] and result = "file-content-store" - or - this = ["create-file", "read-file"] and result = "path-injection" - or - this = ["open-url", "jdbc-url"] and result = "request-forgery" - or - this = "command-line-injection" and result = "command-injection" - or - this = "uncontrolled-format-string" and result = "format-string" - } - - /** Gets an error message for an outdated sink kind. */ - string outdatedMessage() { - result = - "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." - } -} - -/** A valid models-as-data source kind. */ -class ValidSourceKind extends string { - bindingset[this] - ValidSourceKind() { - this = - [ - // shared - "local", "remote", - // Java - "android-external-storage-dir", "contentprovider", - // C# - "file", "file-write", - // JavaScript - "database-access-result", "remote-flow" - ] - or - this.matches([ - // shared - "qltest%", "test-%", - // Swift - "%string-%length" - ]) - } -} - -/** A valid models-as-data summary kind. */ -class ValidSummaryKind extends string { - ValidSummaryKind() { - this = - [ - // shared - "taint", "value", - // JavaScript - "type" - ] - } -} - -/** A valid models-as-data neutral kind. */ -class ValidNeutralKind extends string { - ValidNeutralKind() { - this = - [ - // Java/C# currently - "sink", "source", "summary" - ] - } -} diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index 52962f549b0..d0efe424316 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ extractor: javascript library: true upgrades: upgrades dependencies: + codeql/mad: ${workspace} codeql/regex: ${workspace} codeql/tutorial: ${workspace} codeql/util: ${workspace} diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index 10bea158266..f3474d452f4 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -653,29 +653,22 @@ module ModelOutput { import Cached import Specific::ModelOutputSpecific - private import SharedModelValidation + private import codeql.mad.ModelValidation as SharedModelVal - /** Gets an error message relating to an invalid kind in a model. */ - private string getInvalidModelKind() { - exists(string kind | summaryModel(_, _, _, _, kind) | - not kind instanceof ValidSummaryKind and - result = "Invalid kind \"" + kind + "\" in summary model." - ) - or - exists(string kind, string msg | sinkModel(_, _, kind) | - not kind instanceof ValidSinkKind and - msg = "Invalid kind \"" + kind + "\" in sink model." and - // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. - if kind instanceof OutdatedSinkKind - then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() - else result = msg - ) - or - exists(string kind | sourceModel(_, _, kind) | - not kind instanceof ValidSourceKind and - result = "Invalid kind \"" + kind + "\" in source model." - ) - } + /** Holds if a summary model exists for the given `kind`. */ + private predicate summaryKind(string kind) { summaryModel(_, _, _, _, kind) } + + /** Holds if a sink model exists for the given `kind`. */ + private predicate sinkKind(string kind) { sinkModel(_, _, kind) } + + /** Holds if a source model exists for the given `kind`. */ + private predicate sourceKind(string kind) { sourceModel(_, _, kind) } + + /** Holds if a neutral model exists for the given `kind`. */ + private predicate neutralKind(string kind) { none() } + + private module KindVal = + SharedModelVal::KindValidation; /** * Gets an error message relating to an invalid CSV row in a model. @@ -723,6 +716,6 @@ module ModelOutput { ) or // Check for invalid model kinds - result = getInvalidModelKind() + result = KindVal::getInvalidModelKind() } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll deleted file mode 100644 index c322bc62029..00000000000 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/SharedModelValidation.qll +++ /dev/null @@ -1,143 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides classes and predicates related to validating models-as-data rows. - * Such that we can share this logic across our CodeQL analysis of different languages. - */ - -/** A valid models-as-data sink kind. */ -class ValidSinkKind extends string { - bindingset[this] - ValidSinkKind() { - this = - [ - // shared - "code-injection", "command-injection", "file-content-store", "html-injection", - "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", - "sql-injection", "url-redirection", - // Java-only currently, but may be shared in the future - "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", - "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", - "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", - "template-injection", "xpath-injection", "xslt-injection", - // JavaScript-only currently, but may be shared in the future - "mongodb.sink", "nosql-injection", "unsafe-deserialization", - // Swift-only currently, but may be shared in the future - "database-store", "format-string", "hash-iteration-count", "predicate-injection", - "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" - ] - or - this.matches([ - // shared - "encryption-%", "qltest%", "test-%", - // Java-only currently, but may be shared in the future - "regex-use%", - // JavaScript-only currently, but may be shared in the future - "credentials-%", - // Swift-only currently, but may be shared in the future - "%string-%length", "weak-hash-input-%" - ]) - } -} - -/** An outdated models-as-data sink kind. */ -class OutdatedSinkKind extends string { - OutdatedSinkKind() { - this = - [ - "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", - "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", - "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote", "uncontrolled-format-string", "js-eval" - ] - } - - /** Gets a replacement kind for an outdated sink kind. */ - private string replacementKind() { - this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and - result = this + "-injection" - or - this = "js-eval" and result = "code-injection" - or - this = "url-redirect" and result = "url-redirection" - or - this = "ssti" and result = "template-injection" - or - this = "logging" and result = "log-injection" - or - this = "pending-intent-sent" and result = "pending-intents" - or - this = "intent-start" and result = "intent-redirection" - or - this = "set-hostname-verifier" and result = "hostname-verification" - or - this = "header-splitting" and result = "response-splitting" - or - this = "xss" and result = "html-injection\" or \"js-injection" - or - this = ["write-file", "remote"] and result = "file-content-store" - or - this = ["create-file", "read-file"] and result = "path-injection" - or - this = ["open-url", "jdbc-url"] and result = "request-forgery" - or - this = "command-line-injection" and result = "command-injection" - or - this = "uncontrolled-format-string" and result = "format-string" - } - - /** Gets an error message for an outdated sink kind. */ - string outdatedMessage() { - result = - "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." - } -} - -/** A valid models-as-data source kind. */ -class ValidSourceKind extends string { - bindingset[this] - ValidSourceKind() { - this = - [ - // shared - "local", "remote", - // Java - "android-external-storage-dir", "contentprovider", - // C# - "file", "file-write", - // JavaScript - "database-access-result", "remote-flow" - ] - or - this.matches([ - // shared - "qltest%", "test-%", - // Swift - "%string-%length" - ]) - } -} - -/** A valid models-as-data summary kind. */ -class ValidSummaryKind extends string { - ValidSummaryKind() { - this = - [ - // shared - "taint", "value", - // JavaScript - "type" - ] - } -} - -/** A valid models-as-data neutral kind. */ -class ValidNeutralKind extends string { - ValidNeutralKind() { - this = - [ - // Java/C# currently - "sink", "source", "summary" - ] - } -} diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index 9d4522d5f58..0d2694d78fe 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ extractor: python library: true upgrades: upgrades dependencies: + codeql/mad: ${workspace} codeql/regex: ${workspace} codeql/tutorial: ${workspace} codeql/util: ${workspace} diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index 10bea158266..f3474d452f4 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -653,29 +653,22 @@ module ModelOutput { import Cached import Specific::ModelOutputSpecific - private import SharedModelValidation + private import codeql.mad.ModelValidation as SharedModelVal - /** Gets an error message relating to an invalid kind in a model. */ - private string getInvalidModelKind() { - exists(string kind | summaryModel(_, _, _, _, kind) | - not kind instanceof ValidSummaryKind and - result = "Invalid kind \"" + kind + "\" in summary model." - ) - or - exists(string kind, string msg | sinkModel(_, _, kind) | - not kind instanceof ValidSinkKind and - msg = "Invalid kind \"" + kind + "\" in sink model." and - // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. - if kind instanceof OutdatedSinkKind - then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() - else result = msg - ) - or - exists(string kind | sourceModel(_, _, kind) | - not kind instanceof ValidSourceKind and - result = "Invalid kind \"" + kind + "\" in source model." - ) - } + /** Holds if a summary model exists for the given `kind`. */ + private predicate summaryKind(string kind) { summaryModel(_, _, _, _, kind) } + + /** Holds if a sink model exists for the given `kind`. */ + private predicate sinkKind(string kind) { sinkModel(_, _, kind) } + + /** Holds if a source model exists for the given `kind`. */ + private predicate sourceKind(string kind) { sourceModel(_, _, kind) } + + /** Holds if a neutral model exists for the given `kind`. */ + private predicate neutralKind(string kind) { none() } + + private module KindVal = + SharedModelVal::KindValidation; /** * Gets an error message relating to an invalid CSV row in a model. @@ -723,6 +716,6 @@ module ModelOutput { ) or // Check for invalid model kinds - result = getInvalidModelKind() + result = KindVal::getInvalidModelKind() } } diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll b/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll deleted file mode 100644 index c322bc62029..00000000000 --- a/python/ql/lib/semmle/python/frameworks/data/internal/SharedModelValidation.qll +++ /dev/null @@ -1,143 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides classes and predicates related to validating models-as-data rows. - * Such that we can share this logic across our CodeQL analysis of different languages. - */ - -/** A valid models-as-data sink kind. */ -class ValidSinkKind extends string { - bindingset[this] - ValidSinkKind() { - this = - [ - // shared - "code-injection", "command-injection", "file-content-store", "html-injection", - "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", - "sql-injection", "url-redirection", - // Java-only currently, but may be shared in the future - "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", - "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", - "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", - "template-injection", "xpath-injection", "xslt-injection", - // JavaScript-only currently, but may be shared in the future - "mongodb.sink", "nosql-injection", "unsafe-deserialization", - // Swift-only currently, but may be shared in the future - "database-store", "format-string", "hash-iteration-count", "predicate-injection", - "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" - ] - or - this.matches([ - // shared - "encryption-%", "qltest%", "test-%", - // Java-only currently, but may be shared in the future - "regex-use%", - // JavaScript-only currently, but may be shared in the future - "credentials-%", - // Swift-only currently, but may be shared in the future - "%string-%length", "weak-hash-input-%" - ]) - } -} - -/** An outdated models-as-data sink kind. */ -class OutdatedSinkKind extends string { - OutdatedSinkKind() { - this = - [ - "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", - "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", - "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote", "uncontrolled-format-string", "js-eval" - ] - } - - /** Gets a replacement kind for an outdated sink kind. */ - private string replacementKind() { - this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and - result = this + "-injection" - or - this = "js-eval" and result = "code-injection" - or - this = "url-redirect" and result = "url-redirection" - or - this = "ssti" and result = "template-injection" - or - this = "logging" and result = "log-injection" - or - this = "pending-intent-sent" and result = "pending-intents" - or - this = "intent-start" and result = "intent-redirection" - or - this = "set-hostname-verifier" and result = "hostname-verification" - or - this = "header-splitting" and result = "response-splitting" - or - this = "xss" and result = "html-injection\" or \"js-injection" - or - this = ["write-file", "remote"] and result = "file-content-store" - or - this = ["create-file", "read-file"] and result = "path-injection" - or - this = ["open-url", "jdbc-url"] and result = "request-forgery" - or - this = "command-line-injection" and result = "command-injection" - or - this = "uncontrolled-format-string" and result = "format-string" - } - - /** Gets an error message for an outdated sink kind. */ - string outdatedMessage() { - result = - "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." - } -} - -/** A valid models-as-data source kind. */ -class ValidSourceKind extends string { - bindingset[this] - ValidSourceKind() { - this = - [ - // shared - "local", "remote", - // Java - "android-external-storage-dir", "contentprovider", - // C# - "file", "file-write", - // JavaScript - "database-access-result", "remote-flow" - ] - or - this.matches([ - // shared - "qltest%", "test-%", - // Swift - "%string-%length" - ]) - } -} - -/** A valid models-as-data summary kind. */ -class ValidSummaryKind extends string { - ValidSummaryKind() { - this = - [ - // shared - "taint", "value", - // JavaScript - "type" - ] - } -} - -/** A valid models-as-data neutral kind. */ -class ValidNeutralKind extends string { - ValidNeutralKind() { - this = - [ - // Java/C# currently - "sink", "source", "summary" - ] - } -} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index 10bea158266..f3474d452f4 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -653,29 +653,22 @@ module ModelOutput { import Cached import Specific::ModelOutputSpecific - private import SharedModelValidation + private import codeql.mad.ModelValidation as SharedModelVal - /** Gets an error message relating to an invalid kind in a model. */ - private string getInvalidModelKind() { - exists(string kind | summaryModel(_, _, _, _, kind) | - not kind instanceof ValidSummaryKind and - result = "Invalid kind \"" + kind + "\" in summary model." - ) - or - exists(string kind, string msg | sinkModel(_, _, kind) | - not kind instanceof ValidSinkKind and - msg = "Invalid kind \"" + kind + "\" in sink model." and - // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. - if kind instanceof OutdatedSinkKind - then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() - else result = msg - ) - or - exists(string kind | sourceModel(_, _, kind) | - not kind instanceof ValidSourceKind and - result = "Invalid kind \"" + kind + "\" in source model." - ) - } + /** Holds if a summary model exists for the given `kind`. */ + private predicate summaryKind(string kind) { summaryModel(_, _, _, _, kind) } + + /** Holds if a sink model exists for the given `kind`. */ + private predicate sinkKind(string kind) { sinkModel(_, _, kind) } + + /** Holds if a source model exists for the given `kind`. */ + private predicate sourceKind(string kind) { sourceModel(_, _, kind) } + + /** Holds if a neutral model exists for the given `kind`. */ + private predicate neutralKind(string kind) { none() } + + private module KindVal = + SharedModelVal::KindValidation; /** * Gets an error message relating to an invalid CSV row in a model. @@ -723,6 +716,6 @@ module ModelOutput { ) or // Check for invalid model kinds - result = getInvalidModelKind() + result = KindVal::getInvalidModelKind() } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll deleted file mode 100644 index c322bc62029..00000000000 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/SharedModelValidation.qll +++ /dev/null @@ -1,143 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides classes and predicates related to validating models-as-data rows. - * Such that we can share this logic across our CodeQL analysis of different languages. - */ - -/** A valid models-as-data sink kind. */ -class ValidSinkKind extends string { - bindingset[this] - ValidSinkKind() { - this = - [ - // shared - "code-injection", "command-injection", "file-content-store", "html-injection", - "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", - "sql-injection", "url-redirection", - // Java-only currently, but may be shared in the future - "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", - "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", - "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", - "template-injection", "xpath-injection", "xslt-injection", - // JavaScript-only currently, but may be shared in the future - "mongodb.sink", "nosql-injection", "unsafe-deserialization", - // Swift-only currently, but may be shared in the future - "database-store", "format-string", "hash-iteration-count", "predicate-injection", - "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" - ] - or - this.matches([ - // shared - "encryption-%", "qltest%", "test-%", - // Java-only currently, but may be shared in the future - "regex-use%", - // JavaScript-only currently, but may be shared in the future - "credentials-%", - // Swift-only currently, but may be shared in the future - "%string-%length", "weak-hash-input-%" - ]) - } -} - -/** An outdated models-as-data sink kind. */ -class OutdatedSinkKind extends string { - OutdatedSinkKind() { - this = - [ - "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", - "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", - "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote", "uncontrolled-format-string", "js-eval" - ] - } - - /** Gets a replacement kind for an outdated sink kind. */ - private string replacementKind() { - this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and - result = this + "-injection" - or - this = "js-eval" and result = "code-injection" - or - this = "url-redirect" and result = "url-redirection" - or - this = "ssti" and result = "template-injection" - or - this = "logging" and result = "log-injection" - or - this = "pending-intent-sent" and result = "pending-intents" - or - this = "intent-start" and result = "intent-redirection" - or - this = "set-hostname-verifier" and result = "hostname-verification" - or - this = "header-splitting" and result = "response-splitting" - or - this = "xss" and result = "html-injection\" or \"js-injection" - or - this = ["write-file", "remote"] and result = "file-content-store" - or - this = ["create-file", "read-file"] and result = "path-injection" - or - this = ["open-url", "jdbc-url"] and result = "request-forgery" - or - this = "command-line-injection" and result = "command-injection" - or - this = "uncontrolled-format-string" and result = "format-string" - } - - /** Gets an error message for an outdated sink kind. */ - string outdatedMessage() { - result = - "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." - } -} - -/** A valid models-as-data source kind. */ -class ValidSourceKind extends string { - bindingset[this] - ValidSourceKind() { - this = - [ - // shared - "local", "remote", - // Java - "android-external-storage-dir", "contentprovider", - // C# - "file", "file-write", - // JavaScript - "database-access-result", "remote-flow" - ] - or - this.matches([ - // shared - "qltest%", "test-%", - // Swift - "%string-%length" - ]) - } -} - -/** A valid models-as-data summary kind. */ -class ValidSummaryKind extends string { - ValidSummaryKind() { - this = - [ - // shared - "taint", "value", - // JavaScript - "type" - ] - } -} - -/** A valid models-as-data neutral kind. */ -class ValidNeutralKind extends string { - ValidNeutralKind() { - this = - [ - // Java/C# currently - "sink", "source", "summary" - ] - } -} diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index bb01a5ff87d..d201621268e 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ dbscheme: ruby.dbscheme upgrades: upgrades library: true dependencies: + codeql/mad: ${workspace} codeql/regex: ${workspace} codeql/ssa: ${workspace} codeql/tutorial: ${workspace} diff --git a/shared/mad/codeql-pack.lock.yml b/shared/mad/codeql-pack.lock.yml new file mode 100644 index 00000000000..06dd07fc7dc --- /dev/null +++ b/shared/mad/codeql-pack.lock.yml @@ -0,0 +1,4 @@ +--- +dependencies: {} +compiled: false +lockVersion: 1.0.0 diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml new file mode 100644 index 00000000000..044e54e4f7e --- /dev/null +++ b/shared/mad/codeql-pack.release.yml @@ -0,0 +1,2 @@ +--- +lastReleaseVersion: 0.0.13 diff --git a/shared/mad/codeql/mad/ModelValidation.qll b/shared/mad/codeql/mad/ModelValidation.qll new file mode 100644 index 00000000000..556e233ce2e --- /dev/null +++ b/shared/mad/codeql/mad/ModelValidation.qll @@ -0,0 +1,177 @@ +/** + * Provides classes and predicates related to validating models-as-data rows. + */ + +/** Holds if a model exists for the given `kind`. */ +signature predicate modelKindSig(string kind); + +/** Provides validation for models-as-data summary, sink, source, and neutral kinds. */ +module KindValidation< + modelKindSig/1 summaryKind, modelKindSig/1 sinkKind, modelKindSig/1 sourceKind, + modelKindSig/1 neutralKind> +{ + /** A valid models-as-data sink kind. */ + private class ValidSinkKind extends string { + bindingset[this] + ValidSinkKind() { + this = + [ + // shared + "code-injection", "command-injection", "file-content-store", "html-injection", + "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", + "sql-injection", "url-redirection", + // Java-only currently, but may be shared in the future + "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", + "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", + "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", + "template-injection", "xpath-injection", "xslt-injection", + // JavaScript-only currently, but may be shared in the future + "mongodb.sink", "nosql-injection", "unsafe-deserialization", + // Swift-only currently, but may be shared in the future + "database-store", "format-string", "hash-iteration-count", "predicate-injection", + "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" + ] + or + this.matches([ + // shared + "encryption-%", "qltest%", "test-%", + // Java-only currently, but may be shared in the future + "regex-use%", + // JavaScript-only currently, but may be shared in the future + "credentials-%", + // Swift-only currently, but may be shared in the future + "%string-%length", "weak-hash-input-%" + ]) + } + } + + /** An outdated models-as-data sink kind. */ + private class OutdatedSinkKind extends string { + OutdatedSinkKind() { + this = + [ + "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", + "ldap", "pending-intent-sent", "intent-start", "set-hostname-verifier", + "header-splitting", "xss", "write-file", "create-file", "read-file", "open-url", + "jdbc-url", "command-line-injection", "code", "html", "remote", + "uncontrolled-format-string", "js-eval" + ] + } + + /** Gets a replacement kind for an outdated sink kind. */ + private string replacementKind() { + this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and + result = this + "-injection" + or + this = "js-eval" and result = "code-injection" + or + this = "url-redirect" and result = "url-redirection" + or + this = "ssti" and result = "template-injection" + or + this = "logging" and result = "log-injection" + or + this = "pending-intent-sent" and result = "pending-intents" + or + this = "intent-start" and result = "intent-redirection" + or + this = "set-hostname-verifier" and result = "hostname-verification" + or + this = "header-splitting" and result = "response-splitting" + or + this = "xss" and result = "html-injection\" or \"js-injection" + or + this = ["write-file", "remote"] and result = "file-content-store" + or + this = ["create-file", "read-file"] and result = "path-injection" + or + this = ["open-url", "jdbc-url"] and result = "request-forgery" + or + this = "command-line-injection" and result = "command-injection" + or + this = "uncontrolled-format-string" and result = "format-string" + } + + /** Gets an error message for an outdated sink kind. */ + string outdatedMessage() { + result = + "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." + } + } + + /** A valid models-as-data source kind. */ + private class ValidSourceKind extends string { + bindingset[this] + ValidSourceKind() { + this = + [ + // shared + "local", "remote", + // Java + "android-external-storage-dir", "contentprovider", + // C# + "file", "file-write", + // JavaScript + "database-access-result", "remote-flow" + ] + or + this.matches([ + // shared + "qltest%", "test-%", + // Swift + "%string-%length" + ]) + } + } + + /** A valid models-as-data summary kind. */ + private class ValidSummaryKind extends string { + ValidSummaryKind() { + this = + [ + // shared + "taint", "value", + // JavaScript + "type" + ] + } + } + + /** A valid models-as-data neutral kind. */ + private class ValidNeutralKind extends string { + ValidNeutralKind() { + this = + [ + // Java/C# currently + "sink", "source", "summary" + ] + } + } + + /** Gets an error message relating to an invalid kind in a model. */ + string getInvalidModelKind() { + exists(string kind | summaryKind(kind) | + not kind instanceof ValidSummaryKind and + result = "Invalid kind \"" + kind + "\" in summary model." + ) + or + exists(string kind, string msg | sinkKind(kind) | + not kind instanceof ValidSinkKind and + msg = "Invalid kind \"" + kind + "\" in sink model." and + // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. + if kind instanceof OutdatedSinkKind + then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() + else result = msg + ) + or + exists(string kind | sourceKind(kind) | + not kind instanceof ValidSourceKind and + result = "Invalid kind \"" + kind + "\" in source model." + ) + or + exists(string kind | neutralKind(kind) | + not kind instanceof ValidNeutralKind and + result = "Invalid kind \"" + kind + "\" in neutral model." + ) + } +} diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml new file mode 100644 index 00000000000..2b06aadd2cb --- /dev/null +++ b/shared/mad/qlpack.yml @@ -0,0 +1,6 @@ +name: codeql/mad +version: 0.0.14-dev +groups: shared +library: true +dependencies: +warnOnImplicitThis: true diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index 729262deef8..d55563604c6 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -74,7 +74,7 @@ private import internal.FlowSummaryImpl::Public private import internal.FlowSummaryImpl::Private::External private import internal.FlowSummaryImplSpecific private import FlowSummary as FlowSummary -private import internal.SharedModelValidation +private import codeql.mad.ModelValidation as SharedModelVal /** * A unit class for adding additional source model rows. @@ -264,28 +264,20 @@ module CsvValidation { ) } - /** Gets an error message relating to an invalid kind in a model. */ - private string getInvalidModelKind() { - exists(string row, string kind | summaryModel(row) | - kind = row.splitAt(";", 8) and - not kind instanceof ValidSummaryKind and - result = "Invalid kind \"" + kind + "\" in summary model." - ) - or - exists(string kind, string msg | sinkModel(_, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSinkKind and - msg = "Invalid kind \"" + kind + "\" in sink model." and - // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. - if kind instanceof OutdatedSinkKind - then result = msg + " " + kind.(OutdatedSinkKind).outdatedMessage() - else result = msg - ) - or - exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) | - not kind instanceof ValidSourceKind and - result = "Invalid kind \"" + kind + "\" in source model." - ) - } + /** Holds if a summary model exists for the given `kind`. */ + private predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } + + /** Holds if a sink model exists for the given `kind`. */ + private predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } + + /** Holds if a source model exists for the given `kind`. */ + private predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } + + /** Holds if a neutral model exists for the given `kind`. */ + private predicate neutralKind(string kind) { none() } + + private module KindVal = + SharedModelVal::KindValidation; private string getInvalidModelSubtype() { exists(string pred, string row | @@ -351,7 +343,7 @@ module CsvValidation { msg = [ getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(), - getInvalidModelSubtype(), getInvalidModelColumnCount(), getInvalidModelKind() + getInvalidModelSubtype(), getInvalidModelColumnCount(), KindVal::getInvalidModelKind() ] } } diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll b/swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll deleted file mode 100644 index c322bc62029..00000000000 --- a/swift/ql/lib/codeql/swift/dataflow/internal/SharedModelValidation.qll +++ /dev/null @@ -1,143 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides classes and predicates related to validating models-as-data rows. - * Such that we can share this logic across our CodeQL analysis of different languages. - */ - -/** A valid models-as-data sink kind. */ -class ValidSinkKind extends string { - bindingset[this] - ValidSinkKind() { - this = - [ - // shared - "code-injection", "command-injection", "file-content-store", "html-injection", - "js-injection", "ldap-injection", "log-injection", "path-injection", "request-forgery", - "sql-injection", "url-redirection", - // Java-only currently, but may be shared in the future - "bean-validation", "fragment-injection", "groovy-injection", "hostname-verification", - "information-leak", "intent-redirection", "jexl-injection", "jndi-injection", - "mvel-injection", "ognl-injection", "pending-intents", "response-splitting", - "template-injection", "xpath-injection", "xslt-injection", - // JavaScript-only currently, but may be shared in the future - "mongodb.sink", "nosql-injection", "unsafe-deserialization", - // Swift-only currently, but may be shared in the future - "database-store", "format-string", "hash-iteration-count", "predicate-injection", - "preferences-store", "tls-protocol-version", "transmission", "webview-fetch", "xxe" - ] - or - this.matches([ - // shared - "encryption-%", "qltest%", "test-%", - // Java-only currently, but may be shared in the future - "regex-use%", - // JavaScript-only currently, but may be shared in the future - "credentials-%", - // Swift-only currently, but may be shared in the future - "%string-%length", "weak-hash-input-%" - ]) - } -} - -/** An outdated models-as-data sink kind. */ -class OutdatedSinkKind extends string { - OutdatedSinkKind() { - this = - [ - "sql", "url-redirect", "xpath", "ssti", "logging", "groovy", "jexl", "mvel", "xslt", "ldap", - "pending-intent-sent", "intent-start", "set-hostname-verifier", "header-splitting", "xss", - "write-file", "create-file", "read-file", "open-url", "jdbc-url", "command-line-injection", - "code", "html", "remote", "uncontrolled-format-string", "js-eval" - ] - } - - /** Gets a replacement kind for an outdated sink kind. */ - private string replacementKind() { - this = ["sql", "xpath", "groovy", "jexl", "mvel", "xslt", "ldap", "code", "html"] and - result = this + "-injection" - or - this = "js-eval" and result = "code-injection" - or - this = "url-redirect" and result = "url-redirection" - or - this = "ssti" and result = "template-injection" - or - this = "logging" and result = "log-injection" - or - this = "pending-intent-sent" and result = "pending-intents" - or - this = "intent-start" and result = "intent-redirection" - or - this = "set-hostname-verifier" and result = "hostname-verification" - or - this = "header-splitting" and result = "response-splitting" - or - this = "xss" and result = "html-injection\" or \"js-injection" - or - this = ["write-file", "remote"] and result = "file-content-store" - or - this = ["create-file", "read-file"] and result = "path-injection" - or - this = ["open-url", "jdbc-url"] and result = "request-forgery" - or - this = "command-line-injection" and result = "command-injection" - or - this = "uncontrolled-format-string" and result = "format-string" - } - - /** Gets an error message for an outdated sink kind. */ - string outdatedMessage() { - result = - "The kind \"" + this + "\" is outdated. Use \"" + this.replacementKind() + "\" instead." - } -} - -/** A valid models-as-data source kind. */ -class ValidSourceKind extends string { - bindingset[this] - ValidSourceKind() { - this = - [ - // shared - "local", "remote", - // Java - "android-external-storage-dir", "contentprovider", - // C# - "file", "file-write", - // JavaScript - "database-access-result", "remote-flow" - ] - or - this.matches([ - // shared - "qltest%", "test-%", - // Swift - "%string-%length" - ]) - } -} - -/** A valid models-as-data summary kind. */ -class ValidSummaryKind extends string { - ValidSummaryKind() { - this = - [ - // shared - "taint", "value", - // JavaScript - "type" - ] - } -} - -/** A valid models-as-data neutral kind. */ -class ValidNeutralKind extends string { - ValidNeutralKind() { - this = - [ - // Java/C# currently - "sink", "source", "summary" - ] - } -} diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index f45d347bad3..f5335ce0f3f 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ dbscheme: swift.dbscheme upgrades: upgrades library: true dependencies: + codeql/mad: ${workspace} codeql/ssa: ${workspace} codeql/tutorial: ${workspace} codeql/util: ${workspace} From 3bfb5f9ac4696ee208947e6344061a007386dbb0 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Thu, 8 Jun 2023 20:15:13 -0400 Subject: [PATCH 061/364] Shared: update comment and remove 'remote-flow' as a source kind --- shared/mad/codeql/mad/ModelValidation.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/mad/codeql/mad/ModelValidation.qll b/shared/mad/codeql/mad/ModelValidation.qll index 556e233ce2e..0486a4b07a2 100644 --- a/shared/mad/codeql/mad/ModelValidation.qll +++ b/shared/mad/codeql/mad/ModelValidation.qll @@ -112,7 +112,7 @@ module KindValidation< // C# "file", "file-write", // JavaScript - "database-access-result", "remote-flow" + "database-access-result" ] or this.matches([ @@ -131,7 +131,7 @@ module KindValidation< [ // shared "taint", "value", - // JavaScript + // Dynamic languages "type" ] } From bcba1f3a4dbf8b47c1a9bf04de6577906021114a Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Thu, 8 Jun 2023 21:51:24 -0400 Subject: [PATCH 062/364] Shared: update pack files --- shared/mad/codeql-pack.lock.yml | 4 ---- shared/mad/codeql-pack.release.yml | 2 -- shared/mad/qlpack.yml | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 shared/mad/codeql-pack.lock.yml delete mode 100644 shared/mad/codeql-pack.release.yml diff --git a/shared/mad/codeql-pack.lock.yml b/shared/mad/codeql-pack.lock.yml deleted file mode 100644 index 06dd07fc7dc..00000000000 --- a/shared/mad/codeql-pack.lock.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -dependencies: {} -compiled: false -lockVersion: 1.0.0 diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml deleted file mode 100644 index 044e54e4f7e..00000000000 --- a/shared/mad/codeql-pack.release.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -lastReleaseVersion: 0.0.13 diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml index 2b06aadd2cb..27e6c8e9750 100644 --- a/shared/mad/qlpack.yml +++ b/shared/mad/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/mad -version: 0.0.14-dev +version: 0.0.1-dev groups: shared library: true dependencies: From 7e87a7c1f726d3033016d45de6edbc642ace5c04 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 9 Jun 2023 15:29:13 +0200 Subject: [PATCH 063/364] python: rewrite `argumentPositionMatch` to not use the call graph. --- .../python/dataflow/new/internal/TypeTrackerSpecific.qll | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index f3f9b1b52b9..11e49f5f510 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -170,13 +170,12 @@ private import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowD pragma[noinline] private predicate argumentPositionMatch( - DataFlowPublic::CallCfgNode call, DataFlowPublic::ArgumentNode arg, + DataFlowPublic::CallCfgNode call, DataFlowPublic::Node arg, DataFlowDispatch::ParameterPosition ppos ) { - exists(DataFlowDispatch::ArgumentPosition apos, DataFlowPrivate::DataFlowCall c | - c.getNode() = call.asCfgNode() and - arg.argumentOf(c, apos) and - DataFlowDispatch::parameterMatch(ppos, apos) + exists(DataFlowDispatch::ArgumentPosition apos | + DataFlowDispatch::parameterMatch(ppos, apos) and + DataFlowDispatch::normalCallArg(call.getNode(), arg, apos) ) } From 96bce2a4fcd40b80b63594dddc7bea9ef90a2b4f Mon Sep 17 00:00:00 2001 From: Sarita Iyer <66540150+saritai@users.noreply.github.com> Date: Fri, 9 Jun 2023 10:30:33 -0400 Subject: [PATCH 064/364] mrva docs update --- ...ning-codeql-queries-at-scale-with-mrva.rst | 26 ++++++++++++++++++ .../variant-analysis-code-search-language.png | Bin 0 -> 45562 bytes 2 files changed, 26 insertions(+) create mode 100644 docs/codeql/images/codeql-for-visual-studio-code/variant-analysis-code-search-language.png diff --git a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst index 83dc32edf76..f8b114e34f7 100644 --- a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst +++ b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst @@ -153,6 +153,32 @@ For example, if you want to continue analyzing a set of repositories that had re You can then insert the ``new-repo-list`` of repositories into your list of custom repository lists for easy access in the Variant Analysis Repositories panel. +Using code search to add repositories to a custom list +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use code search directly in the CodeQL extension on VSCode to add a subset of repositories from GitHub.com to a custom list. Note that this feature uses the legacy code search via the code search API. For more information on the syntax to use, see "`Searching code (legacy) `__." + +For example, to add all repositories in the `rails` organization on GitHub, you can search `org:rails`. + +Custom lists can contain a maximum of 1000 repositories, so at most only the first 1000 repositories returned from your search will be added to your list. + +#. In the Variant Analysis Repositories panel, choose the list that you want to add repositories to. You can create a new list or choose an existing list that already contains repositories. + +#. Right-click on the list you have chosen and then click **Add repositories with GitHub Code Search**. + +#. In the search bar, select a language for your search from the choices in the dropdown. + + .. image:: ../images/codeql-for-visual-studio-code/variant-analysis-code-search-language.png + :alt: Screenshot of the search bar for using code search to add repositories to a custom list. The search bar asks you to choose a language for your search and has a dropdown list of languages to choose from. + +#. Type the search query that you want to use and press **Enter**. + +#. You will see a box in the lower right of VSCode with the text "Searching for repositories...". If you click **Cancel**, no repositories will be added to your list. + +#. Once complete, you will see the resulting repositories appear in the dropdown under your custom list in the Variant Analysis Repositories panel. + +It is possible that some of the resulting repositories do not have CodeQL databases or are not accessible. When you run an analysis on the list, the results view will show you which repositories could not be analyzed. + Troubleshooting variant analysis -------------------------------- diff --git a/docs/codeql/images/codeql-for-visual-studio-code/variant-analysis-code-search-language.png b/docs/codeql/images/codeql-for-visual-studio-code/variant-analysis-code-search-language.png new file mode 100644 index 0000000000000000000000000000000000000000..ac0a7d3d5e951dcdc576db9de2c562d98e1bdd31 GIT binary patch literal 45562 zcmdqJWmr_}7d{Ng2o54BDM%Pdr-ag|fCxwqDI(oN4hTpKScK9Ht<=yUHI$%qDKK=X z^w8b#KI1vRbIz-Nct5-!{@0)D8fG(lp1q$~dp-BM*S&b5`aqr(N(aTm!y{F=cUK(` zkFXdI48hk>&XYm;i4~nw7b4OL-&K+h|Cwp@%TQfYodoQA5h*UM^shjIO?M2TJ zUby|{f=9$S!M!u75Y_N=!nZFlN0OhCX$l~Sbn%`ftUR5qa;}SW#!pdozo0;;1YtHvU?JVuF>m_Z#J_fg zN79E+m4*MTxjVA(&Yb{!>xi|L?e9FkO+UEXi}X&8Pke;T{P-fs@F-t8`7=i(hpsF1 z8LqSRaN&iIWx)&C6a|{N*?QA01K1{*Cf}c7yfpdDvB`HW;W^*AHWxf%Q%03|LcF*a z*bZCo3wptefyE&@%opBq$qZeUkhtT!t`@2M^^)e*FpLGup(^XVy%5EekbCvDTPg`= zqr{SFN(yxLttWdokIU0DTd(i%$t5OmkrLl|2i@;j&NL@%)lJ~zG<_@Uzjo;OAR2P_ zfq+y5g-9zwl1lhfyW!k#3J)mv9H$Y*73U+kIyOm@O|9f&pBCI@50+>ZpYN+J?z>l+ z#5L8nFndk@u8LC`n|1#+i;N&57A8iBXEb@dc z-CanmA)C1hrsMUSo$KWLyAP)Cwr#NJj<45Tvr1imY7}4hu)E`2OhM;u!iy_v_cMH#GFZ1@M|x6J5OT->^F6Ykm47hT>_QpyzG+ zIz=66g8RPb1bxr(;bnZhFo@6k?R2#-FEQa|W`fWDd%k3EWkiSft`wflJ-wGgZcCsq zb8!%|?H}-s_~tomy{^Oghxj7WL=~qP{or4S9{F8f#eXeL{w$b{oV3T+h9E=n>M8RL7WxdZy8169v!o?h}prI>uNn!Dmcihaf?E%60!lX{=vD&NJ7 zPs4@$wxlJGg)b4xf86+X?aAeYQ?vE--_$EENS+<2r}<95%1}Y?4I#UVrzTDNoYDA2 zA^Eur{+}4|R;c{!9I^5x<;9q3@!OH5EqUj0Jw>AFC$stcpLSmSn19@S*j=p9oy}uyjcTu2;kDi^s5@mVUg(Zj_@|opx$Y-z5azB)fnH-BtfqDM49`G~kCQSv=14Vyxjj@BuCxRqcn za>|JIM#XEvCb=fZCW9s#Av>Y6cvZVZy%4>aVfig9>?7>$ErKn*EitU2U@ToNT{az3 z2rHCiX)M?&WMRY8Gn(zL>+C@16+a?){K4OXC?+i@ zOPjWuc$NB;E3V(Vj=3JD%$|{yL88p5Y>)ijp<|wHF4iI1VdN~oVY=b8fut@Bj0kKo z4wjvDS#*h+|1lrcyQ2G+dnkG+8WSy{bvEa5&chs!oPqwJe#d@fo_=24$j#yRLyINu zra8v+mPnfs%Y*)|(NKGBxZ6mQ@rp%VPi_5iNI+n~7o*HiUh?siO3kIAouLy635o9? z2t7E}71XuXMb)*V2Dk{OK;bW>CS(Uubba&aN<?>iH zw7Z-hM3DWMT+#T}yPWfbeqMj(pigCjx3yr{zGdR8PqvQ+o-i}pW9N?&`NA>Xc|XoU zM2UFFY|mUF3M7hxNRSAVMV}VwdS-FDYgAxkjq9E658bWH%+KhHS*8@S6y_Sf+$eD@ zxnmL2?agRTU&fUylt5j}e5kq`OuX_uaKezn;xW~Z5^+=9ndrsv1%K2$yQUhvNwxPR%stKC(*2)hLy zQXacOc!gK*c7a)|nOj>;yA9_Dj(*tF(aVEhOM7iBI(e210;_5lsh4W&ntfCZ(jCoO zAB~PL)^zX4F4-JKZP{SFJC6bn>KMqG<|Jud3)9;wQP}YQ)DVnAX|Bh&)zME3@=rqr z`*ivjv(5Ub86om!@`jABq+EBNd|8{J$fXcs4SArIke0}i6@ZQIBgL=|xQTogc1b!X zJ~len{{;IQ6L-pDt1CKLL!x|5eE#Y9-dB=aG(pH~$^kSHJln#&mfkMxGd)YuL)=R- z0X&8^KisC(IjgoBU^_V$1(lD)yb=*L$3eXzXyN8Ejk;UMuBfr>n&pg*&Y*KKp-o*E z6KAW$t9ZuOD-qMeJKG^*CCe`3A=REIejJX*8dpUZm2Ivo;5K#X-TzJg~@h9~_3;@j`n zMdo~cX5KO2dM$p_nM2m3*vjV4Grn|!uR~-LuH%KK!51OESLmAM(ujHSMn>AboVFQ~ zdz;S&dlxNkUwlWTKa)prQuyNHad7R)#d;kW(Q5ZDFPC@YDY*xT_Knc5qh@jS6}z+DGV{D~+yv@>%tVt!(03wIWM zB5~#CH$=fP?ql97%s;>4Vk2=yM_HBmj=hr^voH@I58o9@C^Iv&xRa^5sQO*Gzng=< zB(7MxxHyRN^18XX@wnaKv3IiI<-c|77B8OwuYdqI_y)JLJKV+S2{+vN>R%W6-*xVq zIh#0HIk;Ha!Ng1gZ_KY#Vp?1|OCcY-_rJuEOlUfda8ejYyFf36Lh zisL>NRkeCzW~+PG$_~sKxQC?REk5y|-~a8*zjypkOPzmP@(b_@{I}_UPW{>x=4|G4 z$KDRy(?#;%_4>QUaI%itddxGWoXFIOJz!w}i_wR`3p6P;P}m?M${TbkkG1msFarFJ>@PMkI&xilXB zufMLTqBOI`$>H&y2$H#ygV}y=A-iEgq;Vx4=Pn9jaFc2a>-vp%L1j{cfSB1A@7G`T zh4-((_0qIyEQgre$qIz+hAC+t?tPCsc_ikPyftpG)_Y|3B<#0l#LVGh1Uy;Lq$1>U zom_3QC;~fC*=s&Yz(sR=UT87dbtd}E^3B~_L(~2XYZrg(G`Vz&DRG4=M_q|yJMQcK zyju$eb;pS!M---cIztXj{@L3>lMLxcvLHf${U>!z{RUi$6#1PsbSk@aN(v5-{%w`qMoG zuBEi)syokig+O$3vyFHi8G{ERIbdyz zRV%d_F7rLIB_`YcxOonz0P}UrG47TEcw$plAugvRj2Z|%?;HU`j~BA(A7r+PF>o!y zZ}UD_vN)Bg#MpW@Ox$>;6KP@Hmt}PN+@;u7<(Mox1J9+>?WfyA7EI1lZ{(x1oZGh| zbkQ!^?yL1goyk7O7vEWql;zD2l~^p^uqS7;_S+fv?4C;=-Wo8pFB>vPrb!ZR2jlvq z>JO&m{%YfNAFva@vM+5|t$xYY7%!v|{&O6L+2 z(HkTfd8PZT_Z!umcoN$xtYnwcHDiIK}?zIYG#s$wXL_P zJ#q2d-m5M5yVysf)mfrBiu=w{O+xuSmn$u9OOoyua40Mpo~)^lXP;}RF>Zubksk3}+aFVU z!pz>)w}!2t3SZbM&)UxU6d8wlfC$mtiney1Skd&(?Ah~-TAnx?_--FrzR@K%yT{P) zHgVLYS@38~6Q#-i_9{n9&qNO?z3^ZiKOJ#W&`-xCEkj6L3{7hi{kb;$_y{}oCvPTv z7hciu3ZvJwdNnZqA}e$syrx>-m>(bR71=F>z_SFU-3NQO*GY<9dbehf_VM5mZM4%6 zc^rJn>G{``K{e&(cZk`pMEdgQx8p+@#G3NNta`3(>@O5FbIfCVr@wo!Odb)HWziRlS@rYe{$U`Yxxin_Q%k?=0wbmIb$&3q(C_76gsGOz| z%~`Pzhmq_Wi+EiF51m8Y_oid)U`gcK?$IR?=|lUJRq;}shi1aL!0k>(B)#|2M* z(-!iokgK6L8)|D$jt`0!5Sw4+k=sin&D-anZnUx{$Ci(Kv_FuXe;={9^3>s?m-qKT znhv)KFAEC;w=skxKB{`FD#Za~5B=&Aify=Liyh99)@^_I*laocONDQ~8-KSG{*-q{4CXb$&LoU|uwNe`|pr@$OuZ zUOlto1muXpm5k+!n~F~_)kluc8Gr4};V5?>Kwk` z)}K$KugJjf z0=dP#51-JlKI`lioKT_?-IutxnW&!PFcW9d1c`>i;B`l?RU{!+A|_3*E5@d2Oxd5J z!6UdN3eb%R@M%v+_xDrqW-^fQ;<_CVbaw4P{xr=wo65qq?F&cB4kKDr$Xb&6!uFF# z3o@kn{+bIc^ro%K&E#h%Mr*fFtMWdaM_OO%v>`{x?>ZLOXs^9E@Rh1JAhAte$fQ&PApY&(-zisDBcI zUCL^^V_@~x3UyeqQhU$=oYvwGJwqye=yRO$4r<^bN(3FgeXKZHXF~L%c=$YC{>arW zSrmq?rDYPM^xwi;VAHAe(n4b&b9!2Z5Q%884VrAgN-@P|iX&9&%^Qt0hMz+*Fg+`M zy_Fb4?-zkoL<}zB1}Y=4Mw!ANjZ57=Tby<-CI$RqeTfPqFi0c`g^QAe=k}(y^6of9 zte$z{1#8mti&jYV_r8#HxHYR%EIA2&nAq}7eU@q03)Mw1vyR$>Wt%YAGNILKQH+M^oSA=it&*BWV-&`#FS&V7Y20fK0OR75id;Y5xQd%r%rzV))UG&c2&|Xh!S#!y1mc ziL+8IJ^XXDTUB#iYCaU0s9q^1ge+#lB5(i;&vw`WZtM$oyUJlYN_%)`|2vWHe(p-b z@wpcDF%nqOOj6m!!>aewR)6i**Df%(+<*T`92WxlJ%zZGe!_f>`A;ZG~GA`(P-)-Hw(`qW`wIHvUyj%CczEXzKfKK&ou@BAoGn@pe z89Zb3+EnwT$itHzYd@T!XD93{b?g)w_SzX!uJblq(*1>Is$aO zZK4AUyG;YztBlTO=1kmB-id_`y?=bKz8!=v_L@tRB7wqC%f1HG>qE1n9TdlXLAhuq zt!IIz0&3557t&n;2y8~Lo({;p(RK6FX}ja&4bOsA*w|KI1E3V)flg}W4NlW-LuQzC zHT-ftov2xDLoc%+QhM{*oOq??CB420LJ`A)RzltVs`Qo8lW$NTdbO1m^a79mQAT(- znd^t@ruLp&oZ%WQS^if`U5+17ZQ2K&jD4A~hE<;qP&g4wsgp(ZKqbGA8r(??J{j8r zkwxvi=ZYJvHf_%GCzJCHwzII_XF{;u>>d?v4H>OLZ~xx3E|El&e$uM^ zC_NoM)I6Pta)xPS1bV^;+{H1}P&;%T--K9Lps*O|bPbX7_+QNw3g6UcLR zoj117u1k9Qve~HO>&o$;8y-ltI7Q_gdw3LBi^Hbp?F+q||Aw~LIHkj*aw*$?Zjn=* zDM$^3&{yTR=$?vYf4J;e;ardoOw?NMkwIu5Q@Vd*Wvbv{gNAI<6M>>sgs5;Gp9&_m_-Nx9+WS9n?lsL-omXZUsq&2zJnh; z;nmsMz5*LVJfw*&L~5NhiPzax?!lij2HIocnHj3e25ah8al`<*^76vku32Y~?p8i- zUeU|4Yrl_CLA_TLyot~Zr#ef0G>O0uVlv&k9N4t0u0z{@$U0*t(8AHOm*Lq#$Ez@T zmSx1B%JxOSBBkkG9T6(>*4|XaRgrZ5@6_CSrh=z?06zhb*$CjOQ|ENLdj7^!sXEWp zg|`_TMKS@W8&M=j*43|gYX|4pQ;j;An^R(C8qn;O&kVB>H_Hp4&H zKgk~5yg2ctYNfD?e{hpQ8MjB&3!T~&$z!fhI;ml8>4{4F`52n21A~c( zwGn2iCd2;xDHwAei53%tX(OLAd2Fz2zIkc*@>8x~U z*OQ~2kuO}dA1n6M3cR(Owes}hB)#_Ua?^=QBmxsvRG=b9rKr&;`CQ8NcWpdFQhfN5 zIz+{_gTHwy+xvx+i-{=Y&ybVbk6l+CRKplPu4k;_(r^(amWevL`P?DXDJJ~g-d zBB8L=l{*3xHlB~!4^>su@eE;M9zU{c53G-OM6f$tbz{2|Tbd{4*Cb3C4jB5_xol)cXXV7s9EdzX`Kq%7#nV4D zF!^Aa8?C9Q8NM}aQ!qp?KX#Mz**(fa$j>`QNCnhS>?1c=D{JujTBiDurslG;K zk?s7KESBGIr;oXgbh6Pxh3n$m$%=b!O#q-KQ^4`I@1ZZf_>8}I7jMgYx2{nJM}t3i zT>W@2X|ank#!F3kjAW}^dh9!n)ZjtSrB&QfpN^*Atz{0VvB~9!n5kXPsny;;H($y; zu}~49ycWPAZC|scRTa(jfeJVzQJ))!bh-$3LZ-JvdwbU66L^ivkIB8CioOVfEQ?uYRHPB4f#2MZN@sirD2 zU(GviqgypL0?5U_uP_0`7+eWJ`eO69kW~=h8h2~l5IPr{)E{Nrt7A;p_lP@pBvA?v z9jzeJ;v~{N9L@1g^YXOFiJah*q*l%RyAWOPz_;6(exEUU8dNM$=FJbc$5yMT&lZmg zY2VCtkXzVOo}hw+SRZdG&OYsxFb|{=Wo0O-t@D7spAd{rXb=bthLWJ&R+hU%pC$uT z8can>Cs;_Pw;G@eBbu+ul{v;7vZ|U}zvgmV9S-w$6MPgSzU7&>F$(Cq(JMs*m+u78 zhD2nz_Ul^2f#9-vWtp|^b^wdcf%2F7KP^~#d0vWgaQ-rpb)J5?aH5!7 z*~$?Ube^&wxGTs#YsisjRM*7WldAJnrg?g$ZKJLucH6X6XM-dHzn&a;wXtUo@+ore z4*2BbqqCHW+0^*dtnx?babCE z?;X-|YzoaI0%dY3$yxKKe3b3^ie8`dW>P4LkiP*5Mpo6tsgjk(+7sLMj>mWyDMcKPIL)mUX8S#qb9BmRjJUvrUa%a?eo7^<-<2{v7jlmRp8=4s_KmXBHd5G@t zxJ9y;xm*ZcdU>kyDYq(z8?>e&0QEoJpU-rafca#tD>oPLXHfcAk}Hzz%4mts=Gdh> zcX*qdk*6~0sWZDi#%YT~NDs(PdA6%5}hzCm?|@E$D1>hUHT zu|O9n00_Jn5-ck1)Ki{$TWRs=^Bm8dWpZ!pNffF2ByYMsm@r60#v4ZIfhczVu=C#a zmLA7_zsTb|x0^#5mL>#`YT55O`>^`^3><9{7hhBO320m11J`t2Xowoe>;@2^<9aAs z4)HF(lu3O9?<*gHS5?STy3Pmb!|2qMzsH`g=fSavZ@@D}lBF1f&YBMrN6pJ=!%Wd< zHjw@$I6~q~m^_s>-JSLVhp)mPl1RRc3J0iMbnXo(@W!Y*BuVC2->(nWL(4?p#+Rs3 zhFvoP*?e}(ua9RTmETn;O|5)TuP=(Z+H!sD6NFHpo5bG z2m-=E1@Ca+)zM2do3W+GAm)S1geS}E7fyA_`5w#xm8H=bE~aHyVcJTj`IOV zAF9uZE%NE7M_HuTvCh%4EA{LQ!#n^)Gv#>NU+wQ*@M)VSA%j`}fcW$<^vkB3e3V{2 z-op{LxrrSA!_L(z3+n^{Scsg^QE2w?8b}4a*yvk9`J2R{SzFO|bFq|~Iaavt)1+=dnDa&vR2*#79q?>I&LVxpaQUAT{=ET0@y; z`Nh)eP&L1|1il~>GkZoTt)H{S1y+^4fA<)>PUXsQm~VFc#Jc{dRi`;`Kr>$%HH&OD z>A#hQMCKQC8C*6SRQ6tdcw&{#_lZNvw;)@K?P^KihTmL|aKFr+)Ie#XWE_TBHMbr9v%)d!u zau(@uDwaVo*N1*IhMq0r0>nIa*{nA1@M5#4lv=X3=*lG`J0G9n2f%@4mg zcYgMut3CuoV3~>Uyn+|q+^A2n!S(HW;s5n*2S)&|#5*_r)wlnq0;RQZNM_n>GUfNY zpWi42*gb1(x-R~VBL3S9k3g3l#JW*2ApvrKO(TwU_}`J!f6ev(-Hg~Y9e8!EN5bdm z{@dcOwk;BX!5FQYN#MsV@y~Vs=T~?XNc8Bs58br<&yD`S4e&EW7lG|-ZHxH!he6^K z-me8cYOQNZxcvKFRj+`lyZ_m2>e|1f``?k@TV7yD>jnH4&;RM=Kb?*w21B{vc=6Vm z-@BVKMM7>Gb!gLZ@yb8n|7W-?w|$v&?mm=zK=AwguJ%5WL89}0TaGHtFH+x5Ou0w&d1$)#dh0!TU z)(;@(#A}!T-6Zh*9Pk5mB^Y&WHKT+M`=H-R0+p0GTSR{pmAXbu67@re1S9^v*ME+P zY381GGr2Zpm2d>{k_$vJa}owB{5~)|fBybGJU0s0Ji6djtLC-lN^B< zxHX9EE^fd4=h6E6NRs~L_@Qxy`PP+RSMPqIbpL5xT!^*@(pH_LmCl_&3ljoZ3=+gbzfcIB zkO0vo2VY#0TaI@OB&V#(%O|`K;us}7OkGB7b9YIq_pv$KVwqQu2I`K@&Pg4v{_y#7 z={Il0a*vraAQwbb{o){2Fb5IDo0v2Z70iHCf-p#7hdjKFx!B0v63=fE^d@jPHJH&F zr$*3Jc`+@44|zvI!y_2QsVz*z_#{PSHo3f@W;=clG+iX}&lML}`qgWse1R16w1|Q` zb%Jb|2_NvF{2=J#8?mpe(Jg%JN9uZfxS=9uXh2FtN*7tg^BCOOV>Z#P!*iv^qI)ae zCco%3KkfK?E(aWmf|Z1Ak2!oIb?# zBM(leQOD-E{yhEWdCPIYmsx^rkC@oe^Q)nJ3}UXY^)phKK=zs=hG79jGiJ@Y4w1hu zcH~39T#{lOA5b9oDTuW5)@%ZWhZ&`LcAA_48K!adC1*ad!2=5IJUz2$9s}#P7+!mn zc0rQE$6eEaT(Ej^jjw1%ytHz(xYOGhU`KOLG?(6)sPq9DK&jL8{Sw$LunRKS(K za*IuoO(InwrESZi)h7xi6w->{UWvCKOua*N1IU&{IJ`Cv&m}=(Z+Nk(2}yYo94x zYYCXjmxoJj>@b+mFDOjD$C70A*(q-{hcVd;8Y(xV@K-Q>EMKMIV*FFhUsCUM0^!$E z0+36LtTk!A$iU{RNbY^c3CFs`z|}gFJeMzy_>&Zm62hvNfQm!-eXs8UYSk$UzAiDB z5-^%}#t;*wT0ab&?~)VX(;?9WNkF4D;&A^vQm;LlyHkNR(R5-Vn8|d$}HOl9D+#GZg!__Vf- z6@$cB%7V#jzlDXYWYYPTa9JX%vyreXzXOq4R)%o~n6g-kB zXDj&CGfhQG_k)@2|EePg4Li(OmHQsia0-@x7g0|q{-lspmy!)9`!EL{bz8(F$pgzy zFK%gE=y9E+MI902Pgy!%=}(p(S${yKweLOd)XrTr&ja%Bt>QY$nfHZY zliBm0d6|fwUw66|S-)IBzy_-O@|m?!jzCmS<>eSR+tX#~8+_hG37a&X-I#k9HoOB3 z?K|Slt;DZ^*|`9Z(@c#^Gla{S*f4l)el40l66uyYsb&an1!IN>vL-nA|5R7O*1eKj zncF4IR5F&6a|nB-r|H5vgrr*3S1)KC&2WtLd1=Tf3v>n=V%yxdFxtWSX>fliq7Tyr z(t1Eh@|Kb2=4eJc3WO3hA^ zSK32|nyl`6>$F1V_7#7c(!_5rJDT-HCe86c9yQR_Kd1}zn`e3ASDkVE+~q({I(n|% zNC}^2HJNCpw!QX+8qZ?mVsNZFP18RLj8V=+*Gh>`J9~;q7u%M_6JoT4w6Em{VvXEH z#Cj|1NKw|P6ByB@?-M+(*?H~t6p>%2?SV)3F{nYna3yLzH z-hT)3*AW{#0SiZq6OGy0kH(q&s^yn~y4a@lFO6iOf~)9>r7w9o+Ia<74%k8hNL3Z- z8p-r0+;U#j(STnL!BF*oP%c*qNqx`3FQroj_6WOy`a;CJjC2aqY>y@2kU~il3cRvx zkV!q6lYI*SQ!eEzs)wi7?S~B)+#DgxmX;58b`W44xbt@y8=%o9ZP);EU7T%kd9%)Ml z1`I;WZyx;vaLB#dy_Yp7HA@c%&b9`!;$42y9L|OwkjRE=z)$bsidzp4cQEVrSJ+XdV|AVEGrX5v3 zNYYrFcO}F*6uQCQSFXIM3(3l)Hn%QxLsRb$SIhs8$@qKCnG0|bAIhnDl(y_pPray@ z^^zt8^FG7(wqJCAFU4sphdpHzSqb1_UB5jctzDM#;{j?*>1B<~2c^jQv8wVR04I)= zhj~IlYBYB5XlG)n;=yqQDG?c?Ezkm6#SDC0r+YkZ53rp84re7&=I*XHn~ToGnkbEw z*&V?sYMF#>V@X>+s1C-edy90WL5mL^^XY_bExRNS7AshHv&E(W1h9+d(lzex^f6AW z%QsJQ=}~ayds6i+nyJ=okm5RG3G^+avW zd~c?T(nqqZlyC-@FEVAXQpa=DEjH)Ax~kgc;Z$=!;Yt}?GrZJgUR~^ZjHh)P0V`=+ z-pe8g3H48rr0dt-AV6-Kf*p-lgXf?+C9Xm%eo3ceU9FOYE4F-?tcN>2@<>p?ID@Q&q7 zce1@(o~lZewP+^52}po8t_gSh7^hO7JFQ#12xMel0_jN(Sw%&XyWdW^-7j-`K;`1? z2?VDmvtwCmS3UFk#(EHyn{{H|&ok_Hldw)h>54Q5460_xetIeI>anO$oPO|mjxTsb z1rLA4_RNO3&;(w!B)kE1;jB;FlEiFaY}vO_N^t`4w_Zn^y(*m`DrFSm-j$KLTMi%l zaUJA>^zNzfY7)Quat)PzK|Y|FD6F}l|Ak&TP!*dedu_i!<}C-I=Ag?OD(k%zM;C-3 zTy*wIDkmg19>(to;>_BksfK7lVp$?i#l+02PE8p<5|u;=t(*ZapO>mhRtSRByFQ5X z@^$*hE~Fj>tfx^dKsIBj;&VyzX~no)Sz*x-aq*SPSifHaYv}|WoT1A#Fj36583j4d z^=CIl#ekOc0Tv*;(bjz?$&*9p8|EFcI*1r#CYBziv}dAL>CV$K3{>rt=u7B5fFuR3 z%Dv{RJKoPhni>ktyltB5StGo|Ri4to1%qeXyt9E?3to@CoeRXW80An;Oauf&s*2Ii z4@A6j-Z<2Tg=beGQBj9{N>QrAnMuo;ST@)b(n~k_%1}8E?+XqdknmPNu07tjIUxL8 zxRzl|PvTwz6xIt_3kxFdYzdlfDg&^-&Yb`*h6P-i!KeEWlYFbhJ7f}lbNjMF21GEG z?6(h;{l*ak1{Ms7v9$My30s@>QhLCkud{at3(&J5kjWz=j0^HTvqv#C zg1MDEMK798p!#8dtLpxxBqFcjP{1Kc3J5RnWQ!`KhMnftc8Ijq_?F_6em|<%prtK} zGiDL>rrm1Q9wDNs5hDe$X%$8wHN)S9-LD$2D|$LU zNzB&9h_}q_!jq{izWYJNub~71GSLkpLb@E6ay7HxW&2{qyE#*IvdcL zgwQDB67?PvqhEbCQ2*`_QW}#US(dslj7TX5pPudzGHAaZ60Q|43(;gYHOokz~;=bY10)4H9~rd5^QD2To~TvpFqy!+l(Cq?2#Ypyb-0n&qEi`)K_) z@5&yi<8)uFrA^4Ti{=mf-s1&aR)@iD`;SwR28j8WkGVqsFinLBK+Kngih0WZvQ^{$ zyr%}zWwLzKzi#8WbAzJ5$n={NYko6eaF_RhZj8D@`|6K|!+h;>)p-fV&+cDz^AG1f_Jb#MSaf-j>JLlBEDOd@S+8^H59j`mTt=OIo?2@R z2M(4X1izDT+YhIIbZObSQ)U zXgwFC>X^KDQ*r!o2f+B&ApI6T-&rE@+q4ft2^vLP==hDF>EdVu<Ira`Db?l zOHi{1cJn0xPzq3;ty5&&FdY|H{qf{z;v^17apXII{9qiY`x1pu1HKUn7_LvC4o+Cu zAQb~NsE;ZA4V*iLT+#X8LD>-;aFk5?`F!Izdcd^=@SuWT2ix4Q4GNWi>l2%?pD}|e zj(0Vm?@5oI`W8SYEYIj}dOHah+JPFcAu~X_UDp6&nrH1dZn*ma@^I+s;aan6V7@_B z{JT(54)`?C?!*GRy7K`iC<@K{47k)ND**9yYdlIT0dKt|?w@;8Sn?lF_&-CIh7#yf zn9e8g)NHD20DX1~DB^ngUcobHK~Ja5R@b@Za`0yaH$VyzmAgM)ElGkJ20L7phB(F< zaC;>NBs)VE$yes}?#XHm$0U&cdVSSJ!eWjV)WgbRwWxmK5nBqVLO4~M`WyufC~|}2 zL|sg<&TJ33jR<&Xy&!{9znXg-O$&-yF|!U7Eg&Nvh_Y*58Dh2pOsYAk!80E!Hgmni zjgWZ_ZNBXm`S{06Do$IsmPFTK_G!lyz(-q9Lal5I=!C2X{V)`Z9KwnVR$TmvG5v~W zwtR?#-d!!a>KdRMD6-2~$CXXFj&kNX19=jTH_RyZ7%dj1VF>Fo1KduR#t>DxgFjj8 zX<2`%;J(Jwaa0i%vjy%RhvYe3Tt0)9Hu7A6d?mH<3F#ugKR zPZ8z=<(Y3P=h9xS=cYNk1H9h}3Q>N{%zLyr0RH?HGHD|CE(l`Hvx@qzgBlT$n>7to z49N`@AkJxAGG3o*oxvr?dtH_?l;Vu*xx8f@u^1t4{}-dKaZv?cMAEZ=;PC_2R7 zEZ7xGz~e;&Se3&;ft@k8AI;F)51EA0GwaZ`(6vAu~VG8x-`Rx9WC(kZj=S zx0PJv^-RFZ(TDiq7?GjY{UpXG-~8Zj26Orc-0sT6PHc}ls~j-E_~d?D8(rMm;EFsR zh_Br}&=gOMg}=w~-?L}vL75#;E}g^y)t^9*Tzy1ReoR|uDM!^Z$c5;%P?tGEVDPi- zode28r2~&_XkdXu?-e3m-!3cc2PLGv1%`FvC7P88K+enNXR2b`I14^}mv=A=Bt2h>yK{W*aWlbj;mf*zrfK53AIeQgvollpd=BAtKH=(kWK-m;u(PKlEV)`*}3%Q zXTXD?1bq;WxD03kj)CGq6;7{yA}b%;1gwD-=WFkyEp0IsDq++IHK6jwX*8ko!yl|n zK1BeTW*07RD7mDv;kku13mf3hdC3!^FpculEb0TbQS|F<4(jQV@&30U=1}v82Y~JA z06~VS6bHFxV`M)dHu6aKKvZ9%lk$GGHP8d_GpKILsrgIEPuCTylp%DWJUPaz0AX+s z=peJNDAm8sG1Zuc0W6=Fx}D9+g5JJoIQX-Ec< zE`8#Giqw(m?EKA8spBUHkEHxlU*C>h9;+I$7BwJ)apP)-UH2Y4WamEFlEq7vs^yZg0Ysc-(xk6AOlmTS>%b1U5EKF>b;?7h#ASDuGvo2$J{ zK?^_evvF8r`{y%}Gy1kE^N(}Ws^ZrI%dAuVe5AtJ8non7Q!z_!F9vl<9)Z_4Bgd#y zGZk)@AQmA>N_d&9w6Jy_-Z{lk0%ZB;xpxpn}AR!T@_Qhwgvwton!Uz{aZC{1~ z;;F=l=Y}bCJKl>fDrJ|;8=j|m^rMAI&PesLqv6L5v)TbD$8nn9Qg6@u^R_->U{E&v z*2$^buR>$Nb^rs^a$zpp>c-r|H9I!G(45RKj(CH`ife3dgcqB6`#IJ#Db=MSs_3kq zAHb2jRvi-kb`PZG9aa<|1RRS{EHdlZVj)J9JuR^|l zVy$W6#GhD<1^F5e>g~CbrT?PbV)Cr+i_mEzS{hT2&E*~ewf42~7>7X1fy%OhdVas7 zDy)he+w zWS}DM>9|RkpV1UmPLz4>yt-L*ROVZ1HL&)4PbXK{6IoG^LC)S_|2Bi1#Zb|UN&@tvCrj{G50iRNGz1Grh%k*@Jk-f_ES@g}`y@#~dE~9480{a)Oppg^Dhcbt# z(4jwjit@qX^}c7@a}DiMvxwGdT%WHVR9W%mz(j1!du>~%LDa%l@wC-#Lk~}gE|?j) zT)oF+`Y#*k?>Y(POoHQSXdi7?&W9(?frb%wa5lpwKGA@#VdsZ9b~lMmMpcvhQE{ko zXU0X^r*2udB?T92SoT_-6q8c9!B=GaNg#KBG!yk@bhd>@HLeb=W+{<5C7)6@m4Ni5 zC*q@+3eUXEsRf^nvH?vnk&vz#LL*hJO|gp%L@`uzSjEFC=)E@A_n_X>6){+j#pJQ= z?U&r9U;ovI>WjsnU9&S4Zctcu|K*kh_~rh0$Y3 zN4P-YyhHl6Pa~uOOrRCG!LEmGE!ln1&zY-vH;e6t*|(@3BHvOYw#Qua-t7p_9@n+R;8J= z9I6CQ7tM%!m&YoAhr)-)1ni!Rcy3of^TqSpRF$tC<2HIw9Zh2;%HxdR__>pjX2ljs zg{xft(uTOg-^<_7oPGITd@R;^pdcRF0@cq|JB!qAoSL+>&T!-`6j}6S?QEBvg<_|S zqS!!?-%HY2qCufEhb`Os1>397kuvn6RX5+q4GbKqUaoLYSs<3QErKOmEfP!mS^|1= zN8%;P9SqNZl_>gfh!h>0_PrgzFEztn#b~eDqMl}0hPPHjGr%pb?xEAQtffkHfZ>qs zK&8uy6lvcbFjO7CH*jJkoXIX*K+Id6=7!Z|OkTPBR0TT|31WbHGXRaaLB(y$Sd&lJ z=>J6O8DypyY|4?YBP&bE_-pWV)E=J^D>dGJNvh=h!iPy3c8|oG0se_KK(MoC(OtuF z8)Kw$fP6e{{Lgt+tIuy=R1V4~M zhHdf3vy+)Q(1O}NaU9dBo@(8byJa`yMiQIbWRmK`;icv%@xf69EE5+#YQ0DX|Ac{{ zo>wJrNv;vPCFO|(ehm@dPiG!2^1wXQDv_(++*+R>>(;*&fM!~QQ=GZKgL!#L6|hY$bE6E3vRCUS(O+I!7ufn7fR?> zj06`iJv>d#+ClhJA7G8tem{^YzsWJ%*sqQBVI`es1l>6H@!0kd4lz5viPc z!JMR;VmdAZi}=KeI8>S$pHs-ocGO}f*~c?XZ0*U*Ya-g^hg zTh3wUV;!X$vQGD`GKMsw9DCx2L*91e0rbC$1ow#xno#_F5MUFw+ z3LUqRjgiMP8s5oZuM6VVaV3h;JKxaGN5Vi)Z4{pm6Z69U?*SFM^22^X*k)=!d@8g{d+<`Q-AePjKlmKpNr$4a__9UBc2_}))t4n-2En3 zog1z#Ki7Zjg)U9GP*__I0Hh zrS3x0JhVbSqWIdx=|w1uCTvajXZb%hh&=Ykmm)9MP%tkBv_oi%d*UT4?Uo8=?qcfvLJ z#UP(kcxFAHg&P}m<#|3}mZRea(i?eux>Ogn4r9JPX6eh9TkP6EDH;K~^^ZNV{6@A~ zKearsJ6pGdi)o|4qV3c=zB|%5GoihMs>`566-|Ed=y{YKKZSqZ=CtsSLBmZu)}fA7 z)v(8&blN4}J~4UvI(dC1xv@SxhKI!bKpBTKA8ib~LTjadBhYd~n8ZY{`&M6ln=BI} zgKtax+nrru;wKm^4d%n7icUhxE?L1I@*|+cv(xGdw$qGE#Y*pf>=Tr3OA1GNae78p zSa(mt0J#)3?U|0kxN?Tf4C};9hhSTt4@Xt{(rQU0ZYw%5JU3A3|3YmvbPz_q>okISQ}s~R4PufugVPWNSG}@ z2&Jj@#A@v!LG+zcP&~<=cv7{vmX@zIXuCPk_NN{|4vk{*&DILy!Mj6?WO6ef|Mle1 zp_r;Bu8K(b(@ZKnH=$*+{N{-2oAQIC6?WyLPZqkEG`TLeMg?9PG!e5@mrAcahjHj) z{}tQu8?S+u8Iigw^*^#bVk+}0bm$#KO8Cx3rDTs!`g-=R%^dFzTAMl*XnT{X zD>nMWCoQo~MUcrL`2N+@;j9ZnO(c8|`bOS`Ak3?6LW-SB=BxHsKj|N4A`wD!2bK-H zG*9p+R7+o^*r2(7$GYDi2`Vi z)02M%V*NgR|N2Q%4=!r?y@2OW`~mxcq&oDrXu|l`|MrahSJ@?}2;Bxwacu%d2ufBq z_<|FI%_aWWRDS)dC0sP6?rkHXzmowk2wJOsX77K!)L%Vh6enD?@W)kx8Gq@}7kQ!( zwfUdY`d?R1hKq*LGO-hCZ%~K9T~n8T$+Uw-hTxAvxM=&=8)k(5E)l+OHa5!@-+vB~ zf4wp`94@Noo=s4O{eSEx>i>Y|rWt~kBoGCw7N~bQuM)gH4cX9|p?wcE-E+v_dh3Z~ z7%72Nke9us`+r(neYLXKuENWQadR5xhfzt+Ux zcT19%oO&H)4b;0i=rqj1t7i^+=?mBW1QGo@l3`?#p7L!HAz)tKd@s=Vz#51G{+n{h7nfcDO{8+vzxbXW-z1aCAUm{jz~knf${+BRe1f=J>VMZ{-Ei3Y2V z)PUzaW>2DNRx@7#z0Ab}3in6RTfi1afxh;Fo!+-gAiPjoo$J35qLY2qBp1J;x32r8 z7w9wU=rlpDhJ}bvfNgUgGPV9>2enb_5(N6i@02`2Cf{W;>S>fUrdYwANbl&9~L_g$c1AKRV51XS-ItG+84&UHR)bwXr@I$Y@md| ztp@B#L{aHvD3M^#Fpc;$WjT{JCqCDPYhFuvmE*cRH3pfAyuM9=50ha%$qP(ure?-9c?LyX1RN zxSg_`V(pzI(q`DqTlZqi4FVnHXFIkhP`!xOw(cwg%?`T53*hE1O;;o zV%vy7dKk^j5eC;A!#SgG_74$DG?4FqRk#6<$MOByT#&~GVqg4_xwJ%jy!j}vRVQl&1^Q7JQ1y;(N`F>1aG2rL6M9K? z5v#^*FpE~Th!IbN;Gp}uF{}yi+Ey3>r=_O7C~PY4XeCY zMI0We<`Zr+hYj9%b|2Y`R!>b(u8A@-hPI5zJm`N5_u!^|nba8Xyg59Ey>zeu6s|v- zEU{})1qzlv+7xvdQ%X|c;78k#?2Rbl{qd*h2X-{m49Nlt95f^BU}VYhBs)Ln0hgN! zm9SUgrdcnO3!v>VGrboE(`X?Il&3Va4Yhz!ov|kl;Hb4Bi?A6IL@pF1La;XR;`uw%aJ%>(*@JA^Z^0tLvC`v-jxUeFbtr_WP(p`B?9LS1vD z1FT1HUE1?1{_fYusbIcv!Wjo)kO%@TAmh9?$0fEOQxxY?OqHT3Ql*Ar5$U^e zMS&Zi#(m*M@g%)ec*xMsMz}&E@`11TA2q2DWVCMKKdS}X^ZuDU7FxD+dI?W=o7;D7 zXFyBM3zFyJPs%I}8qD2DZeU50LOP_4@~oIjD|c?~J$T$=JdMG$t>^>K!k!&xyuBK7 z+hH^2McOj>Goax|Ad+%iQ&J{7#j7gIj2XgNkBhPJ&T=&j8Et;Uz-GDm4R=C$?C`-ok6~ z0X3a^ZvxsRg77$b#0&$WX@>OB(#kGmRUwV9R+0H$E??NYFM#4HK>y~uVCFG|&+0&$ zcSsX&@aCxoHpBA5GI%OyOO5Q(GV3)SA!?RS@{>@>$@Tuw*-y)H9=`l&iseFoQjebR zA9kL+-odBTYApzKaGM%C3&93X`D^fO zbu`0KHFrsZ=dh`z2-IhSwx5cN#&groWzt(OPjy9^y%u8J^Cv)u8^|h;^#7>}eOTzO z`qfNlJV4Z8knj4e1xb)=fv6e!_2Vn%gC48=Akvn$(S{e#e6eI&2T#G9;_+(r(q-7n zKO*1C)b+{C4;vn(tMrSCH@tS#8Gy%r9d;Z6UQp6nh^SRCQD;<`_>xj6!A772{n-VB z2qXma0F(IV?5hQ*?2O@rq1e|*zma8i=3@sW z*nVKmMkM;fwCIS}RUYeO$CB9XPVN*1fNhu!j%kkZOi62?cCLJRR^OTXPBySv-T5oo_rI`R9mtKcE*gcsx&Y67>p_FOcdmVjq;6?{mM!p0WoH3_TkFIu z5|Az7w4jbq5hO&orP@2af4&;*t+`N}jP}utyYDQcyg5K6*Vw-QtqFlT;{SiZ|NHOY|4@Ty zmTP-$E=TB=-hR>M1bLX2phSvqUqdvc$QBNU&cbzWs7n;4U!LE&67Na664i+}K#x4+ zn3!wfF%U?9%s06-V?)ErZ`Ijw9NIiC(m4Re21t!K^$PPBA3};^74$uO%UwINb$K0T z3f@M+7GI}qTxOqg48$j~-D#>!9dM0B*t(*DQG6TD4kwM!(7ioM@8iTMytV!P1PLtd z7f7Wu{rqO!1(4f6xvZAJf9=&SO~CoRJmiVga{Lw_UU3+fcRtW7cs{`3cU8|R+P3(y zvSGn>zp|A+>)CO{bv37NqIVVcq}WNYBM@-cAS(P;3EGE_qUaznv~TVx(aT{GT5}l2z9vs`0}uToE>c*3+I-d`tV*|yF{Wa zAY3D%=!^bGW`Nj~TjwA@{a5a3C_$~DG}T{Fy&RMlGnUq(?0B7Pqa}b^KO=F#DpP~i z)yN^~F~3*$R}Ep{plm?*3J$MNLyE(;8HSE+GR4t}1ABe5;S_)Gq}nOk112#+hxOSK z2AvEHU~GDfU^0R2j*L1EK}(3{dJ%Z9US5fRFt)4-g0Zhd`nKS$fzLAl;+&2_YUy2F z`p;s$W392)@K(7*%4DCNNQF{%1+g$!;B(}K zNGcfnNQyVq=w#q8EMK{x?Fbyf5F?_BU^MasMCa6*^9_)YlKd->z%xvPq4b%-Dy04L zK#X>=Dp#i)7_Wp!u$P(-%N{>mz6Is@^-pt%h-R*ISUTdyDMC++IWeFx48VowkkB7_ z8I4va=4wE^$z?ORrbJp^ND+eKmbbsc`H*2eiapftF`=ct4-m5Tn@5MuXL<`(-teoS z5ia4%ZRnU$HqYzzLJ{Qvp0ZD~>omHKoJvtKBm}m5X*yUv-5}|2hPvE*w~E-Z7C_Nx z(W9eD!&Cgyl18mA6KmOizs3NT)_Q-P88A4|3S8Q3n?F6}?O&%ty z6KK$b=UE+XP(ipg{~|MkH!0D1x-Bq&&1y0p7@sKysz zNM;H_)&F6p_>=hggINH&;&WCsuZ5+1k%SH(XiR|vbxdd7Qu@2*|j z+sdjdFkD7r3XvDh_Pe;#bZu^bf6shI@<#8fB;{o_tE6lS_52y?4@^Ho9^QMTXzTTa zI>T&lK_MAAPS=b4iRbRaYLXdG)O2N}OpizrrAX;YOOl1`gfrcf0sIWqv5iQ9!*xdytz&T|}4C_ar5 z_t0CJ`FQ$M$t}Tgm^yL_vW)oF*KUGC)&Bcene|d2PuiEse(RAFn^tMzzIBt!zL;#+IL)ib56^Ef$yLCZll$@FxB>=T}IK;HO7LNam za{f9aA6@&L-np^+C9y6?%q+#qGYHHbcMF#Z=qn z6WVu3bzuj`!qU`F!`Vg)-r@qymPN5E+fKv=kC72-$Tz#WSqZkDuwyb|adCG0?>~5; z0KAVGc$GAO!m2QG&PFN9-Vy^22M1;3#|q~>*=WdOZ2*cV8P0?g%dMy^)p+rCaOLPi zve22cXI%@Q1_Xow6jhLudn7BicjviC~DKAbkYPpO^q{biWWPD^=OQvz&>PN$`%B@PTO4$4YO{<<3In83xb%lj`t9{D0K!v z`yl&{WB+xzzkXBF2q5|b+gl8wi~c|V5s?Qg*9gxB!j&+8{{tE5tnmAOexp;d9qsKS zV3|!^&Cp1Ba{2P*M@^%RU1AmlyAbX~yO~T4EAOg9cDNz3vpm#*T{OjOdkY7t&rqa3 zh25xeX|hACZ=wd-W9y#K*e^|}KXdr<x6FmZdS^C zu(8jEL)Ksew9^mh0}nJZS1}(B!15`nma)fj*uH!Y&3RC_A69wJBjc#>BHU@VPu|h7 z@VQ2MO%DWcGV}9y#Xv71{!M*-l*iV;mhnF;mW()6@)fD>zJ2?6FjHDdfS1gU3EIU> zka65}84eIM9jx+5Z4_zHgJJ-jk{vN1rj9@;8JCP>qx>!lro4KJd60&9*4o^K?9P8K z`ul~5!;#A)dL$10;${mVL6ksI6soL3=g9<4L&hsYX|yUa7uz@v8oxAGhHAmR*t+OC z5Yr1adzm5~V9>&0#$_2o?KmvJ{>UWLlris3F6MZkgU0Iy+`>p-{>96kqaz%XLM0v7Ro{)Y8shkZ|u1Emo%^V|IFax{c5C=g)brzaf)XRb3^+Me0QcJR#q?9it{lhy)t!12fx6 zJ^|p4wT;aN8%h(H6`Eyl2R5`nfs7KB;E)i%x&hyDYk0D zzD%_5Hi6ZGqP&Q_z`3>*#R#Qd$1k-c@z?2%pl+1=Iz0T6L>H#b@IHN$mXh+^8dI}6 zF=6re(If1hy$2hBy8riDUz_n&*!lT)dB370n?NZ(4h{|;0kL>EGO+3r2M>=1jD%u^ zF=#>DRXP!zLHOWta^8j}yzsf3LycKmD~Dg_+f4 zwJed1?dSN@+wIBn=J+h=+q?tun+N{|j83jW5H#qbP}$JuIZJj!nWNeuW(S(sO-!T$ z>xILR$r=g+bG>U87U`m(IM;y3{E(#K_!O9tcrYM?!h$N?Eru{K93dly@keikqNk~ZcHTM`z!dH)ON7o5?0&!$2G`oC3BBYG zq$mGAE^a5RgH+;^zzFW=h$4XL$f)B18hroQK`{P|3odH!Eu%^3Q+$QsMmBLbSAs>c zA6%3x--3|iQq7$x_eGxF9WSS$?9%?{I5UN`uWnQXFC#f5OqBcPO~_o^{P9pR+4o0G z4fj6LB>1(l4+*<0B(Gbo@&DZX?18(!WLUS(w?qiu-Mh!M`-rKTxp`yY59-OzQ;n*; znS{PHN>-!YJ*#h3N?%J~4(3XhPjcmdvT8X&DBEt=ZV95?`$rzzMU*lR>!oVtXng$N zToh*esc>f-JV#~SmDr0X1bKfP$)|HuReX;X=Fj?RE&GS(gf zF|F|-8FNWYOf>!R?aS^(8&NVsM^D@S-lzEaN2)<8oQY4i_H8Vcx~XK`R`NSp z=~&*!anI#=*-?e=JX&0@+jnG|`D!JMsRt)D<=5f)xA3BlLE-G4D^A(4Vh_@6% z1olr#*7L}n%QYxFg)n^FeE`@dK{>wJjzA{po5CJgGF|D69D(5ROh!st1%)R{k>_jp zEWtu~fS#|RqU@qCFWw0zSfwi4tv5Q|AY33{MzQ*4gELbX&N>Q7hy#&%odIV_BVfM~ zkOhYz+r0x+*y(%-lQvD31t-e$Yu3QDu2^s?-hs0b2lKTYen2jP92`H*ofAN5X7hIVcfAl$I?%j z@eYXJsi>$))EvD5z&y9qu5z)<#mu@giTCMll|%W8x8E2r_j7;^`4G}IHUCO z2ZxyK`id+&t{{ULL+q3oj6FtwT&E|rF^*hCP55Sac53m4eS^B(ezKjpZ5F^dg(P5M z)8@zv0`-5RsdobS+da94xN9{;9dp3>1~J^KY^$m-3yH3Z=_&XlfZ!MMzZ=$KI6_O00N8;!_}>~w>EjeYPq-oyln(*C0Bu>pY*-} z*-}EV`@#q4vw-3QXY!hq7q3R=w+&rgGf?AK9s$~7rHTs~v>5c+CG_Y)gpQ#AMTJGKus>L92RC`Sc*d)(k*-3V@D z+SqUl8ph|#kbkKAaHSZvhPzdNkkH0kg*;g8CCUJdK=h=)GS|-z&|E+gJmw>iYlC%J z9DDbD_-zVo|6@Ajv!sDYlKi9GfE1aYMk}D^hi6nPNZNW-oo^f>05DK_2s#E5tKt5> zBh7BhGaohKJPDs=?6)g9_8c?Y$KPi80B(L$cWMIL6I`B;tN9!OxnAg*U*w9uEdQj$ zyzwrMR=O_Zvz^8iojhO*MdSx}#1DE9Iuog1N=p7ESJ2$U84WH-KY$SgCF#PBluWt*yH5 z<$3XR68f%)LjitCdK^4KO5jGm0>Bq8acqhZ<{<*@Dtm(X-a`cL9BK#>x0~V*5X20- zL3Bu?7VrCz(1ZOAFzu-716Kkc-}@dYJINuG?e*^(brIeHDgo{k(Uilt^Mr4s0m2vj#r=UcV52CB&_#B6UkA30P1{qL z(0yyjkbI@W*?IUnv@Js**+B{(l(V2dYn~KoYkhVPXcgE#6|Y}U1Tq5+nFO`Co-? ziY`*H14rHjd6g|Cpe=~pz6?S`cF>&h3bIe2*oA~X`meM{1C^`2v_-x11|^^n=+mCz zCrmL1ZH0DF>ZQ`szS1d4rHvEDC;$vP1>HQhdlg%&v=0w4g(DePzQ9Y!DJdy=_eV1j zAS2m;TB40-DTUkMGwt@h@Xt?9oFw^}498_qiV`kTrsL*@YV(EX!^)Mgh-pXSE@;6r zGc(ITpY!bD!-vaUOCXk@0fK5%U_>5NqhSVySpj*573Q>`ddAa@@M{=bAjVsoNd9~k z6jl+zR_*QWrqH??!yr@ZcxhUH+JQ?alvy!c&cGmMg70$H{f7?~L99Cp&BG8R;A0AW zLXAie=?dhk{py}{eZGMt&o~u#$pY)BG9(CmOVg0%nSj!!Anby6-Id#5KNa0l;B6{9Ec@~d^HX2CSJ`8gD|R? zms68FFfcG2I$;J&F4;1_Jl~#WAIi%XUGduhPDY`pU91vq`}bD=jjXQNuAdF6=4Fd< z(WB7Eh8fO{x^)ERtYcYz6$gB6P}{dC{=KW4S6`Es_GyOx@ad5P)veNw(mOX?K$g$U z$Ja?LO5bVGrY7^6X8!Ae)}=n!WuwlP%{GU@qx;uE$O%i znjjhoMR*z*aB~)DT>f!n#v@`-{@8O^`)wd2Zw*4Y%(UszhLXzCqbwneST zulFaoh2}n$yf;XjN5&Gr%=5}dHD-SJrm#I3DoIhrH`FMPH8adR3GK1j%f6f*AjTGq zzWHHMm_4p*GfPnotSZo{3VN}^WjvhD`OO2mXvA-A5y%Z*I0(KBkY+JzW&%xn{}R(kA?#UN@Xrf5-m9%Hf@` zA7@WwlCw&E?AW=aD*-$a7L-YvG?>kE^OJt9MM;kIF)9z6EWdX}7>Pip2QQCOnt&B5 z<#dQ=E>sSJXNTIIs@MDHM?jDJ-sv4scg=F#6bqg|n~bB*t1{?Hg_GV9o^9{x(-)$^ zEyX&XiEzI2;Qrs;$UbE!j zUB+!^Jq)o%bg4bCk5ISyO*`m8$C1vrr%j_uLB)rIV!-ioR9@nj=a^fuxC~9f9BHhX zeEyC?*1ML9tP!QSCkzgh2B_F9RWXYsBaEh?VwFRpP&zt=IOqQ=8h%ERM)p)WhDPM( zr6fgGDnj;r^P1+`^pn=*BtA)D*QNA{LTSUd?1FXVxFxz{n5pEv;1DPw>T#Z&?LA`I zLFVNX6?6K2sHWg+I}aB>W=cnx4XF?BgX7sfIa$%k31-7igKf*B$#o(P?P^wt#=kQ> zS9$rvr9;n);(wK1&hrEP9F2Adaa$v4-1vtpY5PBTfpn3Ij_zhEzus!ME$|XDviBxW zebY04AIC{gW_U|0)N*22RSKrrsjFXi`7u!+$0Ls&ReUJCb2TX;t7&C^kQ)e2{ZpEepR>cRu;sx1V}okL=kO@g?{w?R$#>tq}iu9e$EpEXj#JuP0|rKT7^ z2{XZYYLKpqP)>DuFC;9#+=gp4!a?4=1)C8!oIU0eEMDXg4Q%u%b^e+%XQyTGuXqy+ z{|4N-ofU+)G}Uc9%!dbZpz4!9ZF^nYo)m*J`#O%+-1i-S*Yz%ZhTB%~aFFx6rkU`IcIYo+%7-w0YZ`%M_I8uz?m#g`MPO`iZZ(sxE7Ho#z*e{s$F)gG(&KQ{JZUFT$ufXz-6>%Bo% z3hk$xJ{*Q==Z^Xy!wj^Iyf!h5tw@I*7~mdaHu@8jU*|#YP$ITLq6^}IaCpo=%{m6; zfQ`YGqcWFeu`fcUhC#$Bd!m7zQ#et{Ycvm;f^66=A%;z(0&F6!%nuWUNG z9B{_b8on|dRJ|lPy%}@5Y^fGL#*!y^J+RQXiOzYTg`D*F?-PqLLj#3>e`AFKmqWH! z<)w>;x0F7?J8R-Fx+Q2zz>3w7bZ;Ndb9;R-nv(sf4+rD1c>Mt6G})`I9qW))ZI#|} zir)sO08f>0oyII*Yt*2Gun{A(wk@LX2wMaik^I7iToify@@DK9i22C+D|pf8)|O z@LtszO71Zs{AbaUK6s=^I7m3UBCSfQt}y-m#z9V68Z(jjHRW5%<#-fRH0TX>Pd;6TpjCxga$y*7qR5I*CPo6z&D7So+;;irw*qBwQmV;%T54 zc1+)dmTgf85Ep%KXQ&}TQ2R@%{Z4To>qYN-2XKg9uG{oUVBksxnOn`_+blFcMnY7Z zT@A`3-GQu=B2f4dsk|z>H7H)fC4NE<7+jUddv^$*p+04G+T8o#9+&ZE69&Eb=6!=d$i z75?WZKal>6{%Q_B7jrAlU_5{A-kUdX?iPUrhg6z`z^WjIr_re4e^yojmePj3BnFCV zU~EyyQH8}~iBg(Xv6#8fLT%$&(5fgk$UQC=QQR|)C{jSH8uaMVqvOWbnA^~-mWLfq zugI#vD8jFHCnKs5gGeEe+7>FWW8a{EZwyk1Gl&-wLaS@H$kwdAo%=Bnph0l*Afq#RK7IRk8v-MrI?nXAB^e!poroDx zcrRNedDsn9>S}0e&K5)S9gDEc&~lm)-igz}qk=+oDuFyW>2%O6H?+ozF!S z(evq=LDXR?{>1huw^tDG1$t>SIlTUB9r0UdpnZa9{MIX1TVHwak%_4<=Ed;*{PPYBAQ+@Ucy~nKt*$1l{0&6nAt5ZPQN@4n z;!z%(N#ki?om%U-A;!eWXdCx>Jr ztoo68JmOw|ZgPkP2t~;!r473~B2_vuMo)_ejnPU&DtMV6t4wz!o(|?4Y0q#%1|Gb{ zv|9SnOTzQkBtCzj#(p8oPk71_`h-;U^j3qHdhm$y#w8b?tCzQ89Rq1QJd3<;{v*sV z$eKsmS#B*H@E)x#1E7k$Q3!xcAgPzHv)#JOm%u|FO6{Eh*-ut+fl)YVHkK_gKe0hd zd_e}%;n1B{ID~|5Ao|mc)i|S4^A>tQm#Xe@O}5xk1CgfB-`+|92^Io~#e9EgcF?sR z{c7ufls_UuX=K8X(9PM6cXPfOVQ$M0mXb?@;-ruJI%1(S|k_Bao zcPOoO^3^L>9*9DCTWV_$8Lz{s>1SNKBs|s}9VXmaZesai@Cc%z$2`V&)eS;xz%CFI zaDk$kb?2rgDNjlE1l8oW7JtMj?R&t{3$g2x1sy#(CsWeo^BHDHS>X-h9L?^g%SQ2l+~n>UYC?sR@V0K%uD=66in zh;bGN)q%rh>}aS7(~fh}#}LKp!(m)KbhE~oyP*$cZj}&lk($Ae{~(m}L5B>jB^A!K zD{nu3osF>M$h)13l3GgJD3x~VA?ATW_mZ@=-WQ11J?r)3H51NbyB2co?5$3o#^F4K zclI?C?juhj246RTk#df$Pm}RFr`ChF4~O~VhEqt(3f2)*DW6lCp8_YJ7y~O z?bRN8NKADV41$EyXfM~=o^-C9RsJHiY4G(40oE3<)|u>-FlJ_Xiifck!AS>qd}sxn zq#CjA+V0Ap>h^M=``&?c90h$CR}1b;yMvw^N9gES5HKtYB-Vv#rO7C5_@8JZnnrD` zR$`~G0-LI^q_YpN=;@OUD7O)|v=&Z?cw{c$ig<|#wa==?*$l{grQ88ez={LzO1S0| zj~xJo)s{#Kf^i>O_LmnSEons54R%mU#(=P>D61;n`2l;?2ohE(hQVP->EVR@_WRLiCH+WA_S-%TCr#Um;cJnbXl5hao%#YxY ziop~P?khXRuA#KZQwk=)lNHYME9=To6d*$F^ua}d#1Y77q;XJ#aUu!#&+yLK#v+d0 zhmK!VbG#f8zCo<(ir)%ORFN;d5^Ndk{C!z5fLM1x;rI^hBxy+ni~Ub=wmVa-eR}n- zqf}I1)#pV&SUZv@h9mY(OlAz&Ycw@9E_?OghP}KT}C!wlJ&xT z;`_?G->++m!HBI4BYe5@kwAiAkSq$71uPrs51?>^;eZvMRlO7i&A%;<4WLy=zz=?5 zb`HO46n`=(FM8rp2Ar>tR8%`j#`h;pY=ZrW9cq#g=&Q|1R$#D%Jw2ZfG^M6yl+flmjOCCtFo_EP3wx zx()&*NQzFv8&X|Z(m|!A7uTD>(65THephaMJT>zly!3mAs$qsB8-Y5y2MmR7T)*CY zeZK6)Cd8haL33H7$O`RX3)9tboTYKm>uo!M45S>~MOqSUMzpSkdM{*r0R1G_Pl+Dd z3BvB(Q-z*cJcky6PeDeExE~Wd4#yEF!6jd%LC;K;mTl)<1eKdI^vpg~k-gtpQIesC zG@)n4vOnzi=l}ha_gS@TQr(}Xsmx~Q&ODa5Bj27^wr5t%<;0H18II!X)MONQhb z`Rl3!L?T9((}ts~k*Fqa3YML?1q>hhP`u^)mF-C6h6_k~BVJpw(}DylR!UYISU$D1 zV_U!9|L>njkfF{f|IfrbHhox?`Jke=XEn%kC2?8U=Htns+geQDVE-Z^R2gjk`x3u@ zB0)5Hm+A(KGdOukw;K!NikGmJMPn8R^O6aw^raBdpjr@${h=Bkf$xu89#-MQd}3Xp z`-ud8Uri3`525?a4UH$MTXue9z)rHZNp-gb3Cay;dx;!kZh9VC=ze$&##-uda<@^i zH)c3kQaR7~m>M{YXEAXRS`FVg)lT_jujy8^{+LvBelFoB`$fruO}=YXQtGj zSoC)Er}IH`&h8VO)wY^VokgDZNgLz#R|LXz9t@m})$2UJT)oyWED{Myl`V&#QT|hd zmp#?R-&Dz(Yrkc1iVu?5+GMDh%l(x3j^VX_m=IZ`&t~xsbN+7MXpi-#RAod( z6-91r=SNnCJluIKN=hnR#&)GUm1eu1>~?Q`lgzGB;_C8D)tW@tYkPRMz06G6VXjBj zHh6!=dV@}HI z5?VaoqeLr@+FZI+z}MrUO;s)da6rk*NyN<6fD?}i^jveF*A;RQSFYNe^Ko}(Lj#wL zTkBoUGyQq3NnZY^YWY&t%Rt9w`giF1QJypik-znP_1)o@^T$V*9lI@ZRGnjs?M#Y= z#qJFIJDG0}6+CUfSu5~tk)W(s?j1u=3KOQ8Vcl#r{Ef|E3CJU!Rf{s89-D&!aP$2^ z3q7*Y&&!wml^%P#<3CpOvq=wZTl;?;^gOS7!qX(}7rIX}+SV5T?AksoN>G2qe7-^0 zW#x(E#^ShmwJk7<<1bUs)SD_RFQErKiUY)EzvZS$guEQji!#^W-eSn0I&9Vb8AMs7 zF4}Gx>SZw(UvnF;rtSn(l&md8%yw2^rt(zY@#eV%hT_C;!_|BA3pZ6)1;ZtltSrip zZ=1(t|JbwdL>j;Yr8VbZ;(n>6sFo3EqosxX`4QwP^Cy?dh@FBv8(ZSFZz z(ljvtKANz*;V!s*TwF&cboM(OH#N(_q*xp2jt;*ou-ELr{cO^&yRddzS*I}f=FZj% zS*W?U27~G5m}>Os!;wOp!L8UkIVp85VaoViv#>iYwkuwrQj439Zm_?MAI|X8J^kA8 zek6Jglg{#9%soq}bJB0n-PuT>#pYIEgpC{)(jl+$n-O>!)DW{;rcZXY*=FLI4lp>&#?d%z*amR z`wyL{VD&BEa@Kp{{K@9f6+-k!BZ&eUJ9->l^ktfNp>sy;M11vYM*fj56X#ycmJf&R zw--HyQaS6@v!~43=c6Wb2aQo1@j;x-sk&(1cJ`lN(Tmo8Z#_%T^k1>P(DR+(5nUpg zL5@4c78*92hskHwc6XAd&5__TIcYXBATlktt+Jf#-((hFZ3Gf~$0uJJxmBK!YT)NH z*$wr33iIL%W(F7PGf%JJvtzrJvl?nI0$Eyr0%y#^=HBdckY?HiA9kQ1?sYm zdCzmJMOo7sLl+fF;k4KuBQ3+cPC8=v+va-3VNyjF8Pl`5A83Q z4+@ii{NU;(qpf;kt(ARwvFDy`xBCyZPxWuB1nrF<{L-l^;?zh(hL%uFWK`PCHp(1%t@~$;OWD?+8DR^Tn&a{B zr@ib>&U&I-3f->P_bhxINRG!pApLz9{_~ThC0zp=ivi8OGx(Gys)OOAe*3mM!>-hQ z$vt~Q!{Fx2+PsPfp4!KsNyY#3OTWRco@Ac2i7@mA@b zD;3#6S5MjtGb?w`ZAfixOH{EZ#!V6sU9lb`av{e#7OaASc|-w4N$2*yYySrV%(7&{ zRT6uMQU}$@3IJmY-1Yc@vy(la>(+1t#od%KL@!QqeH0cs`}WX$qbio)V#-M9HV6OP z*fvT6C}r1f#i8!>+qxHd`h+(==1c<*SR!i*(NOC*xo->Hbu&z?tXxQcNuZ)c7;yVD z=L?4g0if`J=;j+W|TIvx9B-E)&N_msgQmN$VySOZoDLn}vl%oL9?vHKV9;La#-3aJS)> zf~<)d_>Z$2!yx>%Z!QzOSZi(S z_AqqYAbg}#aUs6RGT4(-(+VAk)eEz0ATPdzE5c}-nr_CoWQ;rwwx7fqs3=A}p=nf{ zWjm~KF2+~}Bm9RPI+S!b#fuG^aUpBt63=ZARS=(qYhD%$PAsU2H1|9PtF z<<*{x)4j3@XZDA7qO#6-@ecfvj+9_QlAX|4p_4UGwmi^tV{sm6DbC{@!_tET-*i!$jhi) K&XvCA^S=PiCi?~e literal 0 HcmV?d00001 From c741fb49be493c215cec25ef992f58b92d0d2a46 Mon Sep 17 00:00:00 2001 From: Sarita Iyer <66540150+saritai@users.noreply.github.com> Date: Fri, 9 Jun 2023 10:42:02 -0400 Subject: [PATCH 065/364] updates --- .../running-codeql-queries-at-scale-with-mrva.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst index f8b114e34f7..6d3201ef45a 100644 --- a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst +++ b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst @@ -156,7 +156,7 @@ You can then insert the ``new-repo-list`` of repositories into your list of cust Using code search to add repositories to a custom list ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can use code search directly in the CodeQL extension on VSCode to add a subset of repositories from GitHub.com to a custom list. Note that this feature uses the legacy code search via the code search API. For more information on the syntax to use, see "`Searching code (legacy) `__." +You can use code search directly in the CodeQL extension to add a subset of repositories from GitHub.com to a custom list. Note that this feature uses the legacy code search via the code search API. For more information on the syntax to use, see "`Searching code (legacy) `__." For example, to add all repositories in the `rails` organization on GitHub, you can search `org:rails`. @@ -173,7 +173,7 @@ Custom lists can contain a maximum of 1000 repositories, so at most only the fir #. Type the search query that you want to use and press **Enter**. -#. You will see a box in the lower right of VSCode with the text "Searching for repositories...". If you click **Cancel**, no repositories will be added to your list. +#. You can view the progress of your search in the bottom right corner of the application in a box with the text "Searching for repositories...". If you click **Cancel**, no repositories will be added to your list. #. Once complete, you will see the resulting repositories appear in the dropdown under your custom list in the Variant Analysis Repositories panel. From 112a4adaf248fe65d333e17ac6506e0607b0df7a Mon Sep 17 00:00:00 2001 From: Sarita Iyer <66540150+saritai@users.noreply.github.com> Date: Fri, 9 Jun 2023 11:25:38 -0400 Subject: [PATCH 066/364] update image --- .../variant-analysis-code-search-language.png | Bin 45562 -> 28847 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/codeql/images/codeql-for-visual-studio-code/variant-analysis-code-search-language.png b/docs/codeql/images/codeql-for-visual-studio-code/variant-analysis-code-search-language.png index ac0a7d3d5e951dcdc576db9de2c562d98e1bdd31..5f2eddec6f663cbb91eff42bde8be44a4db296bc 100644 GIT binary patch literal 28847 zcmce7by!qg`z|2J&@*&145gTh7_@}I&?QKBr*zlQ zXY-xk_v(Aj-{)|xxn^IRz4xrO_FB)n@B6t|n8qUoB79nW3=9k+B}If51_o9w1_mZ0 z=r(Z1Dx^&m0|WoFwXCd$lB_ILIO0=ptP=ho!qJtBQww5;Dy-N&&Axw&V%%Jw( zx5cuuftW87_I8fvdHmWIxVuW8UteAOK6v4OKY;{;Jp6S4G$Av3Uuno_pKX8(BX&C9 zzL-;muZ^2?@S{~A=Pc7=E*>NOVvu8--(DK>KJiay43Iga`g?4Ql(6+~TOZQrp_{>_ zQMypl94_f`7IAS|zkSWOYW?)uEHT5DY!@0FYYq>{mL9m*vI?uGy_f{!lf8-%cS6NG#ny&Ur9+C<8C*+0H&$2`5bCch zIA4yiT7C+_Ra<_w^h2AHeaDFN_#|UuRNd$Ju$!sp-onpO3pNGpj^3Wsbt6s-_2KTw zxD$5p8T!#O;^zU|vzh%mR_m;NFO&E6`n}!6NkzY8j5-RwXYE@iHxUq~n>S$6K#5%L z7zY?1CXrw~YifOFhC6Srn5ZbH)cH(R(4#p>wJ_P?LAtf2nI%cXn0LAx!whfR4s%PD z#K&)^gns9P{r&y?kDtf#VYF+cJNqc}Ti^0~dAnhl%qvB}Q--cyMOO+-*^gMjkN7^u zrv}n7OpdwRwSI6AHZv5fCE(PLBwku%;uKa)`1SVb2e2)co;1xE&T&BC97u?Gz46&A zh(6{+Dcq`CjQ;k0xQ71ByO@zu;Gj@WFwuaYGc!vER%xJaEbbBkj;x6W7dZ)=w5j54 z?!XbLU=4`&?JfV$AI$o!S7FXX>p_fC;(Zv0lxJ8h_h~*gPZaao5|tSX(qk($9L%x0 zF{j;HX{4Lesv?yj9BrhUr`u(yqVvHaVZqRpqDC^Bh82T}NdsD#!;s|9{K=tgifmee z05jue%hgvsIH60p<+@CEW|4KQ6 zwGqB-YF4Z?CO76~i{~nNOn%IFOk6>7jv3m_`-)x2QXhkdGATeWTrXzQ|4ZwGc@f9D zDiblrBLB*Unnl@NF)vC9rg{cnYG2IR;GJe)7$?{n&lOuzhF)5=gY7Mt7}7)b19TY# zfxWXrIJ1R-aa!0~qFTILG*9Ot-CF+T#HKN44~ zQ((~fbZ7EzC}-ZiqNftMUTUYo_=c^ztxx4X#OIYhU5;0V6J^o#2?Gz68~!OXPmeUjIP*@rUkr{iC#(4{w=J^H)U*w8^(Qwi&chJ+OOF@m|9& z{dv^$qzQ#1>vh9*nIo*D=SQOJMgqySDB1$r)CcPiGOSDmem$_X;Tf1JaDV3Xiq`x6 zq`*~qfOUJG_)x(2?(a?Ii7&T?Uk=iajPxImCR#a+qH@LaoBQ?#l=|=9hj2GqOdi#qVuLZE)2gwJLUD_F?uIwL70OJ`t$h zQ*%h2@7A>_un_GQ={9jvI50nWeUM679Gno`VHzs8;=Jjcw6?JJZgA&WJok9wc;axP zxDMeL<1hMOJid&Mgp4?jq<+);RzE2;kvqOw=5GGQl+G&EX42|>q-QGH;i>(b$qdsS z%lZLS<5g5(aA2QFUbDBt`$g6E@6o@aXVcQsb00l;bgL(%XRn8%=S0_8hto!U<1@iX z>*R}%UC)ww3m+9eD{MEoeqH9Q;v%|qY#P!@I3MZF?=gKe?Y`|fRU@9vxW`x{{zLpo z%st~>MsF=)Ewwmxsg_4~83z`wmB(K#(Ny_QRea z%iBFud9Xy}&I!~^?bbd{_{uTK zQX_Ugn4K@jL3s~O3AfiXMVU{>U(wg686}w}?k5St2lXmEp7p*y-WR|3fdcQ|`=_*D zyYP4-t>un0=M^;BnE5&KGZf)^*w3E5AGP z#A}LqtpEF8aHbxAn;3lv|cZJ&Bo*#Vhy3 z*1Tp;`w4`pLQ+}P0;v*sjs@XXKF)W34{Rllb8jUD@)*@Eyjj+|S98?#b5@}{0bpXif-$nNnfcEtKpg1uXb4$JUNaME!%dU ziK_Lyo|*ETKEXLL5>xct{cUpG9H;Pw(Ts^oEKA~!`{$$b{WoQ^HZ|!#dXLbD<>Cas z$N5RK=j$=ulBnZl@jNm3+UQo1hsnvprr)eodzUc$+)&9ditzV!!G&e3&EP1<_5Rrx zJ5G!Iov6cKtCL4N0y7M5JG&@%A!qbj=phLU6M=-amk2uLsQO6dFzG5z&S=j_r9Q>m z=7RC?a?k2)H9v@BIVuJVwEoHzhT%YhAr*$>H{#zz;>7-Y%`uQ2h1rI8!I6<%-Tn*D zk5(WuN-m8ZBRboD6UPrm+b*9Cf@4fhc6q-(X2=|DCk*u|**vDn!PWcy4ePo%jOHp7 zbxqT#`viBl7Y)Y{0pXbzN=E_U)%Jz1l7*TY#$DhTgn^Aoi-7|iVFDisOuB!LRMKJvPD)`YA*8k4Ft_S(lM{!(pVTGO{Ot4GQS)dIzz-(^L+;6wMYSd8 zI0$r}FTbtjm{lr-3*X6P7aqwE8hbdHLsp?UIIyF@mW_?fF~ z1+%lTy1IHVMQy8>>T7jugw&rB4U=j}^xMu5_w?$T!){brt$aEBna8yN@jfsdg!KDU z-XgH9CfA3*)U>G)G$jt*hSeyWaE8TbOGNy25i5(7)I)BN{s2vrW9iQy?0=dARFf^v zkH9dxsr>aDQ=j4({JYQMRiWQlMd7n@QrM3orF3IL#qQIib<>!2Jq7DB14Ma|aiA_xB`|8fc8#+V!$6ykx zq<8O@?R0&LipV|>RR4T;kLuGnsU5+H*a?HEE85b3y#216it+W;W!prC zY5-p5W%iL&U6>yzjnF?b!8%tEsJ5JnABA>>-K0gCWpBlIo6#Su)+1k2j@E~})*qW-O|Oz+q6rpg_<_yHnB>(SiRbm@iTID8jx;g%Qt>PFB99-L?~FWv6(zhc zk47uJ&yRC`a}$PR%+xK&W+~x@w(4SgL3T5><2liLf}PPZqa=3uWlk%PW=V16_#{cs zg$>ger`5}oMulDX@8N8%xVf(0at!WUP$4mLK0Ddjsa^EKH_d~(?9-8*;ENPC6+6|U zqTfiO^}t38F7e~bv=L(mvl^WGk0F>4&MWNK2@MO^gIrhkU9u2PJ#6rg8rQ8-J%_qs z`}#}QS)rLa&q{*XT?MN72+;DcFkAXiPw=9TKD`qh;c;3ZSROM-G+G?m_sOT&{}O1* z_}S5h(@yJTTTDS$TW=%zW{Y>k=yI}zjAUBqF}jh!X~8GxEbEb5)+1AgIE+K=?&He}7V+I?^ZfY;)1-8?%hezomuKjXU&o)NBIR$fE zF5_+qdd^#dIm)#4cHQx1%GPDbpv0~%r(fwf?N zF+8X_vU}w7ldg&HHY-?xHW#^A9P~=Q$(*Qka7Z%rC@?as^^$fw`1Q~Zmz+|V&u_zDp7w71O5tx$i7iqs+&^8(-0?mTlQr2~GHia+8ct!q(}>F?kkP-K zWVGEIi~8M@zOfK-v59%>w(iOHbo#whlv!J33Ggz(ewfl?&1vNgc z<<>23uuIrc)vk3~=`qag?Xb-BwlJu1{k}GscW!yCAbA!SvyuL0rUZ^cH=XXzGDtLu zl3!$TuMr(K`w}D>xTZX?>VvK&h4nr1gn<1A73Nlp7V>&Yj<~R3vACF5RR`^9Q+n7q zSWv|N50?!K+aczG@MI~(u0pL!5|5z6j2NA$>sN)(`DE~m{tOY9&jeEYe!UXswv`c8 zviDh*z{oVXepMe1S+;d&Jlk8?CLySg{brDoJ%nsRSifU`*&Hd#75KB*Rr11 z{TF-fOq01v3AJ`pMJ;BwEEB6v%^^fQAV@5-WN)#(hBJ#uCV3BvPopyUNzGsv>aiPU z#c%;mDc>0{%R7+X9TZf>KuAH9h-$|M;V#q!z4L2%nXZDsjCP4b8ZSi1TLl`+1dS9K z%~Hdg&_|<2Z$#1ll42YgL`K9t!YlMt%V{hvGUoA)jqy%F&w-ydKpwC5H{(Dr`>C4X zhjMh-JXp!DAf+~J8w9&4V?T8U#1jFN;3byOqh|?$cq2^^vp`4L4&`h1VA6s5o|RdQ z15;qrC~-Hqm;I~EJZ*3ERSB*cS}ldI^|51dvs1W2nzigi0|C6&Sg*p?aj$3PbWmOL zXeG){Vk6SAKU?nV*@{!An>)%MzW8EMh1$rFno6+#Z2ikrui%;x@@3WjEM)O_7eg;G zWHL{k>AHKL4T*BQ8k&z_Gn?b@r6Snwe;DU*@$@E2`e2jKbNlon7{eMgvB9i}P4uF= zz`G7oh)i}8@nKkQnymvf#Xm@e40;^=JG?+v|xGk6{sL(>NAQA&+yp*w@Al5|C z@8?FW+2)pN-oBFIS*S3M+=RtiDI5}unhfIwjUyo}UQ;0YK1RA zrC3~|7>$5@yp_%7@AngdUg~RqgdmXwiy*wiTKIf|SY$X~$@wL$sG5^gj!8!{f3~mL z5~NCt+}ZKHt^wA`U-d$}ss-(ByxBzkzudyKNxyU8D;rI*d{!3ExXg)>SnrMPRR9|! zoa?VIcRbUf63x^!lD#DJZ3iI)uyi_1cRI#~8E zX*&L$>TtZ$l8QJrJ?>zMsp|VpK%zf}c8HMR1i7LQ*n&BQP`k6Z*F?-qkdZ7xMzJwF zvp_h-MWxaN#AhxC08dhTFleJ*ZANG<#NQ0G+n$kWreq{F2c|&~f`6IQNqALVFa2b) zL4f)NTJUjr!!cyjU=1>O0ZEGNCtJgJ?7bZ1)fN7iiY*|{LwUZ@4s?V8TxNER=~UGb7R0<#ZHZhL8abuU=mXgE&x zqGX0rP&6!4)$PJZr=$&K3dnuAppC;{@{L9ViqyBZs7YY&&p~cIG#tIFp>aZa5_B$M zNdDUy!q*G}_ETd;p}pB}KKKIAHk<+zZ^raUXekmzuL1>8w$S<>LKrSIf5%ANA-ph; zNyeAVgSDVpRI?Z**Y-oxC5Ohci}NH-AXuRHuQKU%VXu%7!F|&bDk=ex&;(^Jv;|p8 z>MiRA{ahR-WUShL4@82PbLtge$$ocy7{k5YszUvyin5;Rf`m|LMJO#)@N}!BoeF4_`4Dri;xOd#KUsM34SIjw`LnuQAZ@o5DCrl*a zccW#9BA0vZVJMMTYo;-QQP^)&V4a%TJ@z_=THwCu#7 z%vUp?aSVXj*1(20*R7N!zDvQth>gVX)rHV5(UAHtTCRZQU;{rx?n}o)Nzu)b8X(E< zX87~XOy(1<*GRIDxe{crd8+0D^!q~;W%{7x$nrQ>Kd8LGZhIyQOnc$1BJhCR>qP`r zk9G4BW7}Rr=0yvR&}gRDekYckPC>*R^FVv=H3ANKaM2wJy{l+4#k}9OBn*2!1~o<5 zj+aioMb1ffgOTV*}|k>_hktoci3Wp0dc3T!O4$1&a%)c zGqXpw<*j84{+DInhb*teIo8WTiT^*FgH>1F_hg+wha8r@Xxx^v|wD=eii;+qDMx#rQ* zh7nQ)Yi!o?G9iXjYIg1Rh-z#@$}mWZ^MaW} z%};W-JDVdsq(hfNE~=B|BmAl_fuPgHr-EG#YrYHn4!fOWbb~agk189ZG45+06Hfge zq+Ur)3QUoUJ?{^iXW$Bd04eC`7%K_0Pcb(I5M{sf@|PAHWMoHjp|GJDB@FAoA4nwcw%#u3 zRK^EMZQhR~Oubl&o+G;Y{enZkoe`oXLFN_WmgrUO$Doh)ij!$Dmql1l^=t% zk#-r}m;1{BivbcGwi-#j^WG=ZN$0`0GpPwOO(c?*;ue{D!6oYJI0ek*{un-l*Z1lm^Qv_R(H8fW#DEOoe%{!qa{{+BFO3^oc?zD3 z5p)01eV?Mg9%BbmHq z9Zz)%Ce!_y5JX_Bm6TcaY(1FaRTJG9rd5GkFY$2|>LTW(5lY z>yG6To3UIjT%GT{;U(eFHI*!9_J{y2aQNW&f_Pi2@|%O$3z>g*lE`zx7*7|ZByI2i zJ{6<*hT+%oN&KtZ$YJM!GM7FU-Gs!80#(d;XI zp+c1k0$rUilkhBXt2V*TLcyQJPms@<=@o-NNMJ>Dz+9`NjbRGOoNT^hfoefqlGkLy zET54WbJVFr%vj-e*f>qZHG56M67zJf*6N}y*hgdp6_AdxJf5pX4j*uw+)y9YC^bO< z$Hk_q_f=+yw@({8Z71#L@*If;`aM}DkXVq7qNWsQKZh8aCS7EVyu1VT-49hMGVhp_4_8Bwo*oIYvSawih zT}XY!VV1|H)eJAT@an`ro^LF*1L>fuS{_>&`|GwEWjwqzOR$94E)Zm@XYgail4B${ z!Heg+Zln5%uj47svc+BI!-=wc_XGlW)6n`0p6IWky^KwX$B4A~-j(;g&?7Wqb0krH zlT$m@MCeKcQ3mrh(OycH`q?7QZuLha!M66I`(jBN@bM~VHEhJ(AtZKA+P(ZLM1tTP0c8o1|g=hU;| zSv=?WqmAJ+3bo=V!s=gRqWVI3neRR;jIf!sBYQ!}&wE9+ z1EX$_$jgGKi#7oX2q~orbSn4VfprC-gUiXFFvUVHNoleymSC18Y^snkqFV?l)6BG| zKJQ7^h>-JcEdoQ5)1EDocer!!HUwTwF08Js{m#7t)GTEl0Heg8Z!T2>)l~vZO)-nz zK~8Do)%1~go_#24A|K}9J@iVQ~A+yT#~Y7-@IF8rrxNMTh&W)?0U>tVKMzx;C^ zxZo8bpulyVMJ&B4_*?ZuN?F5VrOm0by0ipHYd@~_zvTM+HgHGO?%j{lOrXD&&H+WK zgc0S%$HU1$RsJcj@f3G|XZQL4Q51n^vjPB_HuG~E>tB_ORgnsKNEJ-{&z-=5G7HdO z18D6B?0^4|K34S?fhEJvMW}du+w+ePNrZj?g!rGm=&iEuy#P&w9Y_>JeMjJrOb{VACL_#@eY z%y;0m|7j957<*)^qvZPFY}EDmY3SCJjg{m8JlA|y z+YTF|_`BVJlq}m!_$4L9LhppJqWpE|sF|YAgGMuR`=0rr2oZ{ZL}%c@-&6)#Uu^4- z?Z8VDI`v17zWEm!`>US;CyH-r#NKS{PXdA{-kZYPfBFyT$k>-y!7w)__a%s4orlY3 z?|0sR)dN^}O|bH~+}27=Tf_U~!NI2MLAW3Oj|VXMo91b~*`Bf%b=~afwVXarY)ItR zvz@H4TVVd{UB#04dnK`TF^Zae+;}MN&%h^V_LqUwF73cL=^nf^mptuM{|d-z5U^sf+gFQo>at9F)(!*f7X z5#^7bZx+HOqJ3Mw(SYxm`P9fH4S`&AiKiWs`}3YT8?o`_cKNP=T!Q;gDR7Pc4T~l) zj+PxSHVLe|*zc-vT$HD>x0@(0u_>%(Kgm1OfNw$y$kp`q06ZS5@FN{9fTJObLr_>QqTz6v1@;)lm^3d)}+rs+fE|8FCAIE-%yPWdet~ ztA8YDbF3uCz~^+C=O@skFV)45-ny&}v_2NpeTOwa{pBhAgah7>9P>FEermV3(7JsK zMxHg1qd>Cro^5)@`^13mzOkS8VZVYrF@OK0|1I2!>Xi(e^OK!QTqdu+3WwS4Bj1D6 z*|BlU%q^d|0lzvxeDB%OOnM7$Be>VH*-B+(`yc6&1M3=)1fKV1h>P#{Bw?)UyN#BlI(*UjRtji+!e4-KPfLfxdjgCok8)CG z_xWI|iP9Hco556uLhMogoa``ifBB#)hgp>C^1G)$sJ*tUS8RX1e_&6>e0Dgf?s@36 zJJ)FMba{3p_sx6j@=#syc~01~1`thw%~S*g|Vq{1)B2sDcY#UUNjP|G5s}uUSQ+1HARfc*cR%RG+F$5{{j%I4;8s&l0clAnm+?@2nhW> zPNv^@9wylUNepL9#g=j)2co|pAoX$kaBc9L@AZ|S^QuPuOqMKe&B=_X!PobXvI795U$j zFGa^9hzJ^fQ{iVpZvg`E1X8k+>5Hml=JN*fCN;_Sv#7c}KB!@@$Oacxh4%VTL4x>U zpDg1Z5Dva%ssm~u%K|f>DndNts!=yAz{q3mBV$P`F-qcMx48$)UnOgrElGa?E6oYp zO;>@&|10cIjQbcRl?5`yrjv=!90~idpCDoiiR;XLkR890<`k{KcM9}bgiuawnX)|( zWU^{buAAAs(^F0e1*C`=hgoOe<#WaI2)`h{>%tw{V%7-)$u{MT zR~<)cBP6497fMc~q5>praz>ZJ{xTIe*tb4ygZ(5OsFYQl=KzYbm8v zn+DPi1^5)>o}6^Y9+@~~q$MCWmr>>&z0SH8I1rHaj-1w^hhV!s(#`gws2!J`s8zb&}0rSOcUkANLFGNHqco? zX~Mr9CKKiP{pIlMl8)Sa>@S05%*j0g2wMYs$!;8s=Y)s~i>`=-6(H>IoXRPd$f0=1 z8hnn+GM5YY8`LkE6$B5xVdox4>+a-9ijHCi#(<_R-@~7s*yM(M<-|?i1DUpcdvUQM zK@V>K8VNBv5gPM<*z^=&J^u|0KWY7QnzK2CJzzn()KHHUf#5kpvf2(4HrfbIc0Lu> z_%MBhFQlOSbdl*gSrm`E$`2&>HU9H`#|1=ha4UNO*caW*vR|sHu)$A7`QFvz|NR=lfl7r;XiK=uj3(;@v6(wb|K%LM5?itICg-K;1lJ9VN%a^~SVCqO;{$;)w zz*Gx~#rdznwz7(F*j^flFta@~Rgpq3Xo z@=^OLh+3rs<5EM;G=5Y&lkb!}uY^~QFTS9BB(+J7LQDlmh8wK1NW%LJ{gYy7KIQ)H z9-RRDY4$c7nt3mH#HS)v3TG2C&EDfp1kwj~p9aUsQoKl0vTUfmxA@)jGbQoN=)#F^8wxyEAbiq(dkTsepe zjKG5=4;KSi&JqqL-I?e#B0Hb7E_SaC+3z3f|HU)xg(gi&dyQ@ON2#f2a~gDo_& zGhN&euYbY(2>h#<0456OeWZu5*Vk=#@(J9!Xj5uQLAur6FZ{py`OycB*KTCKzu{{d z;RC)1PRK+H1#|cS?h)HxAv2}nj)L2%_0?$o)%R;{qxaGuU)p|6Rf%@=8V=V!VypQJ zzft0)mCoTjFBJ$X1s#~TshU6SpH5)TyGhvpPtmxK6&ydHQCz64@@HxSb2L0d${!ov zB~)zse^?&KA7WVz=TI4lPc(ZyrnSRRiQM6AAj9pi%m$yo+aW|vf&$E}y9xWn=zW;d{01fd{@q1$p zNvr#$=e{w)`Kz?vooSTUYu|ehk)O`UCP5!bxhGCd6E{PoeUmZ%=O=~Iu|cb!6cz;d zJ=#a+SA!1B*=9iwRuB0hR@~bChW~2qBLe?gEt&v+9MW2C*VeQoTjG&_ zJriII@*kwW2$1t>sZv6;R14@!<4tj;3LZMOup^|1tc}Yx<8-1lvK$>*fBlziR%W0h`s0AX1s)PxuFT zAq@B-8Ml|#*48?OQ~hv*-(o)EK3;qVrtp%Ogp!=U-~I?FS9|wAxS21$zB_8eefpj? ziOFc8f$M5tmVV{n;NaHoeDg7YizgccaSigfXX?)LMXKKsxE1?e`&2$@SpWRDpJkWZ z|IiaaXqEI&fpm2r42gh2JRW~i0L z1EN<`h3&X0gNQR{N$n%^?$7uBJFuZx!E#VGh#@vDr1Qo_lHqe^4e+%i&3^stEM#Mh z<&(WuUJicO^jsc8S@i>1K}$~#W=EfoFA^40YLL0i**EVQN@CPDq;sR z0-9;j>N`FiUNrPMAv^EhxNsB1pXlA&TpF$~{NwqN;=}4ZAc`Lr3$w}P0)TpRTQq}> zsmR{Ty*U z&MZS}0#r#qJKDY0XBW4A(ab_jf91J!hVQNdkY4}q{OX92QpSNZB=ks?AKc{T0Xb-& zbDo@D77fjx@z~%7m`nyi9`J(30LW(wAXb++%JmR&J8trlh1)0Ja>e!?C3qpehU2^hQ3XA1_aQuPY4zCc?PPz;6+Gv^hR_ zDLr&!=Q%g1v`;5cYZC@M2>=C|&@>f|e27xewjV2QWLJA{ZsdLRE~XB^Xfscjf4(y? zKVS=V#&1~zm~x%_N>6(F9W$9Bix)3Ws{q>a`{ev+Vx%=OkIEEuBF_1hdSw<-fc44qHq#l))&g*q>&&5S`Stfv!!kCNMD$n>U^<{G z2TTdy0j}6)XJU1BxF%>fA#f70;=A@SiFR>;<}dxJp_3HNWA0W;xo;h+Ax zME1q7?nlIIUWUidjRjvroGkTo1xEK4pqrd*#!Ej|Dxm9u*St;EZ;jv*1IHn)&w}Bw z6tfH>Seh%ytgVMv4E?%+Dz*XKs9sOr7Ma{Gv1mR;B7PWKnZ<;{j%1RY*}6}>IY-sY z#Ew1(>@Vn~pw6GhG26igPgdDRKxFC;jsQNX)47X*9ZAJ@u${{&`J;|{?S)WR6 zo1Z-mvdjvL?33S|R{`%K?X$-~b2p}hoLrzz6&H5vm3-=WlJNZ2Dutk%#+0?vgfNgF&84HZ>?Sfqp{8>e-h9p zZ2CU2-p-gyVc??*%zF)d~0$Qd!3sdWM`uRyy?vx3eVX zJ_!mi8p>*kX})}wuH+R-;tvQIa&v&wYMLcizw67Z7y$^jhy=jhhvilPe`2k}HjCTd zElhltHigf(y!jZ{pYSN)8brRD>(%Ls=aV2x z7?p{9qu|PzS+&4O+ef3<`Vb>>+k_B5H0+x{k!C0-q3dosD&G?pi~?tRo@~3AMEjzF zJ!+a(Ervd>1??}1Zs318)&=W3EXisrIKpj>|FDr-=u;ob(RkB?b*;P)!4*s3GE&_B z*VuRIY$5q?`$)P2nDj|{$>_YS=NRu0d(nV`R}efdyKw!{zwpwdAgMTzA-zmXoR42V za~>IHi~5#6$;M&G1JCLZFl^ZWVgwq!a7)%Jp0P2+kF^f7W~qR5>!Y|Ul5v2li9kA3 zE$G1lX=7KNo_%%eV=y?UyjjqtI&==^g1JY5pzl{iaKxFdQSWD`w+`XB00{0JhG!1`2eZ3@nHxs(6RI_UF?6|rSMlVeBiZ*6HTtAc$<)V&c`Ix zGt%F~J*t&%{V%zuBebEPxzX!x#yWQkL7d_M4cG(u1^N;!gA`*IWoCt>E%m{|!J5e2 zsyXSyxb@vo$&1FvkdD(O4kva)=APAiNdA58u$ciylMqfs5VJXC0%^2w*?B3aYmzi& z;*-(Nv2R`7CLBPm*<%i8*JdtXTS4Ia#EO9T6Cpo9R_smUyA8MGU&?^fIyd-Cf?Ix#J=t_24cA?9;G1OQx3_>U*w#v00g2<< z3igAMP|PDdu&@Z`DO;uhZF&Rf)^_(>?Ojhv*=T11kaDveCK$yoAX}~ z9fw(iM;Yf;uyeL#?}{aTR)EwwAV!LZhj++bXjFw#FE9p#KY?%}ITD*qKVnS4GLpv- z>3t*je9lRZ!gxygFs%syrv*6~gdIyY7rYl4D|2X?l+W2O4@*VLdYR-HX~DpbNL}`r zV4tf4Jg(ELu85UYPD{?jh+h*qoj`Sp{b#q%rh<`>3&aZ?>tkTnTX&Gt4X(XAHVCQ8Z9^bjJP zR7Bk~6MxY5jf-Fk&-rTdY%6$|VhDH|*V@7X{Ut<6ySo-v-HIKk=zJs0rP=I8zc#L}bPfclKJ8 z?y*j&{&u=}Zt88@wnHYptY+;{yBCrt4^`X?%NMc624Fq5wU9b_mSauUqpCJON07mO zkP`L(8hP+2ND`#qq;>yOazmtkYSC&f+BbfKeQN4m$8mUa{1PTM zu4NGZIa51E_V^##sm$mP(+jO!%8G0MgRY=hAN>J#Z0#0K8~A5LAf++@(t3c%q5FS- zrBn%JZLLrM6=nXv(wYE-=1hFaS9@dwq(-hL^m_gRG(gmwGY65YG})5p<1wkWpe zQB1eq<~>yMcl$fpVznAoh_|mU&u<7EkATfkzR8m>IxdZ2#Y8f&Wy$ZKWzyhx)FE4M;V0)9k19WhkdLtkUSs9m*uz2~Z4&X&?rvS_$ zWcsXKuy8bPX=!=xvN`lkZ}evpJkzFTNkYe+=MP1OfkC;dyD;cO+p#%oyn8xdcae8Z zj{*I&@}Nhww{>lQxy!CQnb(jc6kIlHB)eom$ z1p@W|wb7j>JZR{1`eO3CO;RTC&_2{j-Oe*$H-kP1P*&?kfTU$Fj$yq|-Q^svWHG>T z#xk!jEJaVIoT9``3e9Ss78$w%F1_a#78dr}V^M!E!C-$<73huWT`7~OA@SDS#6Pyw*5v8igO z%Vf|lN2Zr4a)HO-M-`ae;~a1ud6HKs#4z%_UCRM{&#r@N51#?ArtT8RVs75JyC(rG zUjbxdbb(Ztf$iha{DV*?pViS4elPT^FVD(88Fl^qS-L%4qq3W^9xAo<&%{7{NCqn^ z1tqO+-;gkk8P`cW#(uT{AjhThhp0o4`Zk+Qt?-64)QFqvFCvijs zWEBuYc89`+oqmrMn>4?E440w%t2%%@#P0tVWT*uJq*JZ1eApvMZ7x34Q20}<)_v;% z*7NBdA4`A+mG-2I>SaoJi>75A)A2THtY5r5#l5Q3mh(4?W@hI%@cw@9T=i^d)yl59IU&S}QN{^p1J2Q1r$n79JGB3Rv z*KaG!ze6b+MQuj7GLw(HjIIU_0tzHw4sq`A*H=t6x4-C09B=TyWx(oW2YA>SgW2na z5LwlQ|7yx>JU}>$*E??_fV&AKvDJfXn0zlvrU88lML&LdGV74brSE+-oY7VcB!Xi` zO2x+ausI;6IxbKb|60ACm0zirOx}laD+i1_anR%xD6lI;D6_BP)x69}RHqXnJZAKI zZ*v3nci7m2#_~0Gm6~v2{zn$;h-0|{9JTA8zjzJfXpsOJMZ4Z&dpC4aSJGy^vMriMAfpi{0vAPC~5Dvl?ixTkku@bY;6SbDa)w`N{+Xn+6 zb`*1vtTf0e#$)M(&pqn9M@mP?+(!wQWal>T&4UFz+aL+06!c)`l{v6)=S$ICgGVEJ z;Dhw7qA#oVAHMx9$9rMX)O$F-d(x#^DLF+S)=J2pKr!QfSZlj_%0?9bib$%YfMY8m#vt&IJpKRcf&P)&F(NE1%|I|*nJ(__ z>FM$Q<`9feu?eWmJ{gILzt1%|&`(fa?vlBN9v(kN^LnymLtk$N{h0XEl{cm{nEzXR zL+tf|k1F1xua}U+z@`|HH`})F?mj66{3)rtW+8y{r5P}T*fj>=@Pq)nQ>=k-(x$xl$M7ypS|Yj|`I?aKk{z;i&9+yo326~IO_H^duY=@qo>p%>k$ zJ@^XPi7KoI*>848+(>@MTa%Um!7sg$wr_Tu{Yrg!VzmpL{dTj4wo*JrC(r^Dz7AN& zM*xdJ%pol3Ujq&SrSX5O`kduQ&Ff`lbxo=6_-HBGTiM6kH9LX>l#13+c%}8=C&q7V z-~8W(nly(1c@~O$I!p4tN}kkWZpBZE45xuyG5sK}p!VOO2mys--3i-`_pGs>7NPnI zn0JoxEToeG`F2=t9mpVvUsnK9jA0BXH(5WpRMp}fFdsxJ@-`)lFz+NC2ETt`m7PQqMfN6JW{Sw(v&cxYNBz$G^E{urzQ6zO z(5uz zWAm;;1om$c0+`Kol_}Ln%*l7@3J+n7S9%>wKW+!QWqo zLVFS)+_TC}yMKf;Rg1{c0RKjb0Us>){x+xcam@pi|A{7`o@|6l58MklPy8bae5V2w z@fFEyA&NxD#&ijso`>WD_8d|ej8U^5ujq*Ua*#`bA0G8TMtn_`7!gb8x{3&v_}-kt zV=)!e$?{(P%V&AN@%ZlB$Hsx|0yvl+Y2-1ySFSZfX>hxK?(F1&BAs7QfT(|7A0+fR z(FSd0-b-UL%3ucM9U`U!;jFLv)!cjk^Li$$Wsu!4;DHd}<3Uth#3HH5Lh#7-Lyev9 z(X(Cs*J4IW#omV~4X1k3uQl;i?>GQCp3r;6L^qcBD&vxBP#TouYx2Wyv)>g0}AEqK(S_2i&Txk&?AhT03C1m_+dKHZjfYmhgJY=#G* z1WaH?Kw2tWT7bOg^T;^}^yw zZO0fc`JNovCubJZYy-C=xs*C|eZJoms&b)HH20=k>2uhIfb_EihmR>P9dg~%F`rT6 z3)7Wd25+BT(@wc}BrA7YCqW~@O!^`Q2667|E5-P6aL65-9;!5@o^fwdq0G-I4KJcemgC2$qud0qr zo-ZJeEeft3Q|CjdMa02~c+x5ivDN6Cduz0~4hdIWA<&%A#^*r+EQvMp>PPA`Rk!>4 z;zEW1#WdSAKAINsuC!nH84QA|w*#|^Q>;6ZwdTL(l7HaZKSU4ye$2n*lUuotj!t5L z2h4PCiF{l~aV|P|yri>sWUMAFVNtLpKs<0hqf7qbSjHw|v`Ygwpjv0Z+MR`r?M z{}=Mv7G$LG1E=19jNeeCSNue)#*G~v+$Q{kY;*JSsSFCWl&yh z;Jv$wq$dYJ&X|qtboH}?bqWi~L44=A-IY^_eNpfZXvi?J`Oqj}DpSrn&3vi_g?nPN z6s%gy-86)$d?GCnfkJOcVT7L$57%SQ32&2@L7mmCRi7c^t|{ zC%QoR6cpKd0+?q%5t|bJjSjK8sxo>YQR+WqmKqAxd2HHZSsP=gMf3N^aFGI~2c{+G zDwWq0UnwNn5Z5G)%S;QgHwyEE-gf0Zvp9Hg?>*jEAxyj6OQyVXl1z&h!p48( zZgEl)%l6^V!@pK4*J3aSO+1VIBhN+ju}Vq~Bi>RLg;1xC`0(&$nzw9klN|s49{d42 z63fH+#|Is+iS^;<>w=cPOigLS9KX;=Z(E2+SH~F6PbFYB<&Or0I4YH%Y1=hfIUYXl z>LlLvQnHt7F2H5a`%8dFsj74!X*7H2*)6eS7RI!*eo>z(bU5C?JZlZ&s(ZGbJlYl{ zZc(egn+RJ3ZVC59TP>{^com1keoDIoue|c{(93j;n({ zF=fv{eVNqEs?V+Fn><)v%$c_ySU_i3 zefz&vK#`S#S6RzdeHb@6{;Zo02oG~882N}a?zNg>)IV1H5Tty!wHA)&+6CqxGcQN7 zi-J|3g-qo=N%#=ZP&zQ|X90I2YFvksV;yz-ny{Ahdn>1>%<*=-uw_J+ep%;SK-K^F zd&KeBxGR_Hk;!`P{s`i0M6Cn#al%wUJrCv_nT-{cb4@MXj>g- zZ&^f5>d}DPpT1UPdUW{cshh|K6mSsh1sr3TFzqB}{vM#GC^;!>m2DBS4_|(>mc%Ik zC`QGLufqUaV(``pSrae_?&nN^-U#qV;GJzDhtdV8o`{Lyi21S?rjB5=_Z5OMC7g5w zu~NKJi8BES`X`!?s;#*_l}VRg*kY{rB8coX)vdAoB^lXo-*Z$8xIq^8%+Ek;+h%mZnAc_AZ*)&+*uywiQ(jHf`E)XgBvpJxdhsmcWV^pu*NTc@rO(C=dKw^^x@u zIb)xI$a((w()HK{e|npxA){~YU^8%ZmCz!7p(yYbXwZuzT-4Gv*bv@KRW@GA^Q~sO zMuR*r7r8O7K_?xIGvA$&?Gr4oOJMS-^5+Ly;~dLJ1oS47$yC`|#P^Ol8T>5)P%#Bv zf7IjU0*)l$C|=4eAu0Am?_X}F=>o}RnN^=E+mv(EqgAtG9Jzy-8ny+vtWKAdHo1YqeF4U1)rAN-kYsP z{|;*qFyE{fMsd59^9VI6b2Yz91vZQ+!j1VLJ%2npInIMw#AgMqb@%2V#4iR-WaA-^ z^&iC!A6Qu)|6sf!>>M7C$!gNmHn|74aIKz7b;DOkgMu(3C_rx9D&g16Pt{vz-^b$L zU&_eeHMct;eiI33k<=;b-?#B?&X7m4STsbcnB3m!x8>30%+JfSbLMsO_tAue} z{aGH?91^?pt#NKvo9GfI%~NugIL&GtPsOTDa-sb2zB>a4FZCPFR zxgnV;o1xMUaNG*S|8p<<$D{EGZGdlpMVZS9|pvuYKJ6&nxQrFYe zYQHyJJDo-|Z)R>jpup&9rh0L=aJR{OCjdtKHh_s=t%=n>f^-K}v!Z+~p*Ay<2MMth z*^Z6?B%G3s77hRkxgSIXYjiW1z;vOeBX%ys67Yd(0c6*gQ5pt?qYrW@b0+tIwE@&4 zNK=D$`o@y>um*}ymile*B__VA_3RY!sTqMr_Aya%uvsq~N^ejHXddTDupQwWB_Nyh zBYg(CfJ+NotZU)PS|s@LkLyy>mBb7E$dVwW2PT4~ino3g&W00VU7mHz^DkK&eQS zl^F!BsSgZPnTTJ=Cho~P2(q8$IXkpFd8K}Bm?BZFpzb)K+XHFpFXv$+(UR~Xs}=CK zHHI;M$8G|BzHY(q`RU|n;IB^ps>er$E8HBBu$F!oRrDp!&o>~$a=~4{FiZ>C-u36j zmPUM%N2#VECKVB+jaq_$Stjr#q9ASD9Vkp!xW-Apr6JTx&{Phd`6osHi zl;dYreIpr(ciz;B_9R5YB}{{h$|td1BraT`Khwvl*2=S0r<@0 zx*CcQRP>$%n-Bh=GauP__v3@d=(Y5aaYMoqvmwJ8TSzwF^wa5GWUX!T zdxV#8x$;yvua&R-gCBqLv+Mq9OK0Ok?2L%qloa?bs%GiOspq!{OLBHquo$QKPB%AA z8liQ#{NA=exTb?ACJX0w8PCLkuh918G69pp#UdD=H@+P&OhpM?-bR*EEnsF7PEYsu zz%Wf1a$sOqQ97_jkwVZS+pLC{)a9RZOc6n!KAy!YGc;-dgSJju-Pe5h6}czsd9Ld2 z^@3DJ;--hMAT?Y1dBH6+of|F9?tz#u&(yMMD5Fk{Z+wzFUUm~ljg<;~mT$vvc`!xj zv97cvdpW{5^$0%Yxr94utRfuk>}44=!y2#_`p@Fh9PUBfxyH_$1Z{{zOr1LG{E$Zozrn-Z4QVSMg3_BCgLhc*1VXEx$^jlny?KO$VOhr<>uwf>}Z`!I{51AE=G23d= zEmrN8ZnoilFIw)9%TVWYWZ_SbAa2J8sZxHVb}IYiC?dsxR5NY=D6hyOjET#s{`Iz+ z)rW8{xj1Mz{>jX$6DuKu!iZ7G+J6So= z_k4eWR#n8KvoDQEJfRlAuP6rZLXfXYN+vT&y=`(+u`9Znga78u&Qllz(R!wIH12-f zjNdskNdv>S8cFs%b?ssNke&t&Mbfj+iO-CB=5Nso4zNgB29Ym&1x`h@JwUTv0p$?K z<#R$niNVkxf1F@kznCQRP+y!%=NMJz6CQ=?C8oE*1~Dh)X0C=VKSZ!F+LgUYKnum| z^R!NUCSFkpd-|UZY2m%Kb%r#`<7>jbP^J+=(nxL3WMKu#-I-ymF}(!aNa!B4>}z8`s8XZqpy(j%-K8?J^Cx8O8qS3k18DTzRv?r(voaP5_6zUJz z3Z$qQ!b`NM1-jw1!-7$_8%}za-srMINW~YY@&;uZ)v#imW68*F=6V1l#;NrT}MSho9N%nx<=1wQ#)SmAY5edJ}@ z4DP=#M#yMdJeI1W1zXf|nyfdiJ>z~;D8n3m&QJ325x^e((0$~(hvv#?Ob#Dh5bFyS z>3;FIe-fm*m=H%tBCoB3>0q^YH3YG@?I~jCsT}Pmd&NfpW!j!DP@izYG$66#a(lh5 zkIl`wF#Xc1nmTLhi-x4tRKYQ1u$qMB1IpVG7Rhz zfnF3fYo-Vrkpdf>7A!a{2RAn_2S?NQYqp>pAuiIv4{<`)kkRC``#o3v3mVb9AQJmM zVpKm{A4p{lvKHSRpipo9yHqe!=d(47Qxo6_QHpwCxeAaaW;4(8LC1kWcGPoZ7v6Td zc3!f9UG2e0TIiC&4@)p1j)-3@~W?!zHs;xJb zaEgevqZ|N+q{B9l%YB(T1v^g&KVjwN0^)l|1UeuHc!h*M8@i4k1QeYY4IbU8iv}To z4i-Mt0I}?MHksx}KLDh1(8vs~Q%ZWm0>6ca$E9)syXyjav|gTSDTa~g?oeso*J-S1 z*$5D})uN`2M@#%H*c?z@gUd43HA4l_JooAoNKQ`gG@S4P}JhWB)*IQ zPTiq1IT@}}7{_T3ugUHRz;?%If&Lx|JC7rJYEC*>V|uNq+0)t9K1yzxJJ9)vc4eu( zkhKxBr!S*%{=*-_2eo9xH9_gd7Di+IXrH`VwqfOf{JG6?w2{W)(qBO6l#a0_>^G+K z<#CcYws1riM8vl?+pzaw`TD^D?AzW}Yj<=3zGos_A7u-DSh5HoXjLH-Qut8KqFvA!P^;YwmEFk`zSa*9kzZ&S2hYYj zsRiynK;%192dE^ob&I~K`)s+2IuntNxTGmc#r_nL$4uHS9k=2Hk~59GcZ-mPoWMzs zuM_qa(2-b@PyN7N(krwW-z>oymMMhtQuTwXDuu*E?&s6j#XcK!tvxwQHsA8@R{j8$ z>IGwOpvEKvp4`Ahs$Q__%hlgDUKqX^ASHLzuJjdAPlwG}>`-QcHq00dvDt`O%fcG0 zRTs7%S+GU#XAVZQM<_eRRv5C!si(cWb1XBjweuFi7+VVG=U`0NiJ9TZoUi#tUTC`N zZ?rQ(gUna$vss!MF-Pw7OioKl4LkQ5R6Rm1a81#VI<)fgJ$WZm{emdQ4~3iuk=^UL z=qCzp75ej$#QtP*3CyLe^js+Fz3=A>CDwgKQYqfu8!&-k&TIF(H8J=w9+6b7UUoJ`XX`k)1J*NY%z%ZJ`tYAjk$rd zNPaLSRaSO=Kg=l}XKfbhUaGJ`!QNGOo&P~b7FQ`ilTypXm%j02Ds z)Y?n0UPl)!({{We^Lw&phYfv0OrbnL*OR)&)EIy9V8}E5Nm`Ym!&Dm|ZrB!+)1GgC zO|1Vd@8M+q(eFoRhy_E)YChdZThPt@dQe_+uJ1v1kxubh)eaB+TIK8a*7AqfTANPx z`!5`R|vw`_fDFs-!Gh#ms1%THf1h^3X~Aqjczh2*L@)ed%zp-g#j;BOh}3dI@ykfQpMj6e3j^kNnE>96K5)#%^2KCPgsdicov@cg})NLUgzdY z;F0@rMe-KIVRoWAi~LCth|)f0J~7Xt(=4#=5X2N^+{kqa$r!k;?6Q#&m|^~Eurp`v zK8x4O_p8YkHV<{9t#q71in=%n!*rVO^_ot0XBjUjb!bp|%(rTm8=%Fq;w_8bXy!)K zuj}^wvQRQivBfkn(A}`#J}WxE>V9i?{LT(Bt)>1+_yh%^rueQ#x8cr5onk>3rvU?%^ih61`vIpQRE@xbAUt87}<{a(cSIZJg&HO6XY`vBvPv8jK1iccD=Z>%}6OCVs;4 z!XA#S$&MFR$LTY+_OOvW2zn9Q$5waVcgqFPpI&_& z{laymydd9t<@fB}-Q<}i#zei-mAeaf%aar&Gt|o}toxmrbo*a~FZADQX7_sAvO+es zgxaGrC|df`RNNK4EuX`7b^Qhvjc~(*7HhqiL!&vxiv>z2KJyAuwzl@(?jPXY&TOYG z%2aZ)o)4JIG>=+4m!x2DSA*lTdvVt6#M5Wvg+4ARUx|F`Sha7YDZ+K}!Dn>4zzh`8 zSmRsZI!>1%&ZIB*^uR1R&SqWkGVdd5?_$^2)}x-Ee&UZ`;yOwgz4y||f1Z;OD=8^y zb9Ik%`_>cb_be6m#VOxxhTT4Cr@pwHpcLag_V~!a7jnVL?)!dzy5SEN2HyIAom>oK zFJ2{t>SP(OMIXpLD9f? zxxk>S%l^pLS06?fZPmBizdtvA$&po1#c-#8Oo;x>>M7Zp^?M~Qg`y#6^{y6P@6URu z+m~J0FFGA$F`>u$S;zj~P}Hi6d{p^h))jIOryZq1`spPtLUPSsjs9Ps^Ku;_p+m1z z`wBC`sFRu^lizbAnp`5onAPR(;46l0>j9sI9u~?hmFsfvBZ_O@9L;R?_?p|JC8g^U zES9~yHY+csL$0oD0A9&2Hb1wb7lw7>?>p$7da}1+?AuRMkr}S{#P9NL<(`E+e1~rN zR9C+KDLQ7Y6_Rtb56wRDgdG!96 zTl_eQw@ujrtr`AYdM{J!MZaHI`siCUqfxPlSKN1PDFnUbzp%Y~q5*A5X0rbJ-C*C+ zPdc698D5*}K$NhoZfm&2nOznl^_PO>aemaHt!93^4`fFze{9~$8?&llAd%3~viTa* zoh(+wQ2hIQ9RKbuD&}Q+`uIJr6kH7%^>~P7hY3Dd@q7E3rwTm}RV_?)3MRgo=7AOE zZ+A&LN@2(FB^O$IhImB>gbu??k+-3|eQz zJ`=Hjwh83lZj8E@WGx1(-G_)@h&fK-Bqu-tW*ZjkWu3PMlRxxhY4t^PAtz* zkztJdc7OOjEixG_bHd*-{{fnsZNK3tMT7Orl|kFi;||Ld5-z;I~ zDVo}M-*XNxuCZ1sF5wn3X-`!rle);M5qUT{N)k4jdObZe28|NEC4)h0DZ71@` zt@Na8No=vn6tINhQ;z&ORyRs??LhAF+VUS3x76S9jhk+-1Abo;haQGx^%jRB6g|RcZQV>-48hk>&XYm;i4~nw7b4OL-&K+h|Cwp@%TQfYodoQA5h*UM^shjIO?M2TJ zUby|{f=9$S!M!u75Y_N=!nZFlN0OhCX$l~Sbn%`ftUR5qa;}SW#!pdozo0;;1YtHvU?JVuF>m_Z#J_fg zN79E+m4*MTxjVA(&Yb{!>xi|L?e9FkO+UEXi}X&8Pke;T{P-fs@F-t8`7=i(hpsF1 z8LqSRaN&iIWx)&C6a|{N*?QA01K1{*Cf}c7yfpdDvB`HW;W^*AHWxf%Q%03|LcF*a z*bZCo3wptefyE&@%opBq$qZeUkhtT!t`@2M^^)e*FpLGup(^XVy%5EekbCvDTPg`= zqr{SFN(yxLttWdokIU0DTd(i%$t5OmkrLl|2i@;j&NL@%)lJ~zG<_@Uzjo;OAR2P_ zfq+y5g-9zwl1lhfyW!k#3J)mv9H$Y*73U+kIyOm@O|9f&pBCI@50+>ZpYN+J?z>l+ z#5L8nFndk@u8LC`n|1#+i;N&57A8iBXEb@dc z-CanmA)C1hrsMUSo$KWLyAP)Cwr#NJj<45Tvr1imY7}4hu)E`2OhM;u!iy_v_cMH#GFZ1@M|x6J5OT->^F6Ykm47hT>_QpyzG+ zIz=66g8RPb1bxr(;bnZhFo@6k?R2#-FEQa|W`fWDd%k3EWkiSft`wflJ-wGgZcCsq zb8!%|?H}-s_~tomy{^Oghxj7WL=~qP{or4S9{F8f#eXeL{w$b{oV3T+h9E=n>M8RL7WxdZy8169v!o?h}prI>uNn!Dmcihaf?E%60!lX{=vD&NJ7 zPs4@$wxlJGg)b4xf86+X?aAeYQ?vE--_$EENS+<2r}<95%1}Y?4I#UVrzTDNoYDA2 zA^Eur{+}4|R;c{!9I^5x<;9q3@!OH5EqUj0Jw>AFC$stcpLSmSn19@S*j=p9oy}uyjcTu2;kDi^s5@mVUg(Zj_@|opx$Y-z5azB)fnH-BtfqDM49`G~kCQSv=14Vyxjj@BuCxRqcn za>|JIM#XEvCb=fZCW9s#Av>Y6cvZVZy%4>aVfig9>?7>$ErKn*EitU2U@ToNT{az3 z2rHCiX)M?&WMRY8Gn(zL>+C@16+a?){K4OXC?+i@ zOPjWuc$NB;E3V(Vj=3JD%$|{yL88p5Y>)ijp<|wHF4iI1VdN~oVY=b8fut@Bj0kKo z4wjvDS#*h+|1lrcyQ2G+dnkG+8WSy{bvEa5&chs!oPqwJe#d@fo_=24$j#yRLyINu zra8v+mPnfs%Y*)|(NKGBxZ6mQ@rp%VPi_5iNI+n~7o*HiUh?siO3kIAouLy635o9? z2t7E}71XuXMb)*V2Dk{OK;bW>CS(Uubba&aN<?>iH zw7Z-hM3DWMT+#T}yPWfbeqMj(pigCjx3yr{zGdR8PqvQ+o-i}pW9N?&`NA>Xc|XoU zM2UFFY|mUF3M7hxNRSAVMV}VwdS-FDYgAxkjq9E658bWH%+KhHS*8@S6y_Sf+$eD@ zxnmL2?agRTU&fUylt5j}e5kq`OuX_uaKezn;xW~Z5^+=9ndrsv1%K2$yQUhvNwxPR%stKC(*2)hLy zQXacOc!gK*c7a)|nOj>;yA9_Dj(*tF(aVEhOM7iBI(e210;_5lsh4W&ntfCZ(jCoO zAB~PL)^zX4F4-JKZP{SFJC6bn>KMqG<|Jud3)9;wQP}YQ)DVnAX|Bh&)zME3@=rqr z`*ivjv(5Ub86om!@`jABq+EBNd|8{J$fXcs4SArIke0}i6@ZQIBgL=|xQTogc1b!X zJ~len{{;IQ6L-pDt1CKLL!x|5eE#Y9-dB=aG(pH~$^kSHJln#&mfkMxGd)YuL)=R- z0X&8^KisC(IjgoBU^_V$1(lD)yb=*L$3eXzXyN8Ejk;UMuBfr>n&pg*&Y*KKp-o*E z6KAW$t9ZuOD-qMeJKG^*CCe`3A=REIejJX*8dpUZm2Ivo;5K#X-TzJg~@h9~_3;@j`n zMdo~cX5KO2dM$p_nM2m3*vjV4Grn|!uR~-LuH%KK!51OESLmAM(ujHSMn>AboVFQ~ zdz;S&dlxNkUwlWTKa)prQuyNHad7R)#d;kW(Q5ZDFPC@YDY*xT_Knc5qh@jS6}z+DGV{D~+yv@>%tVt!(03wIWM zB5~#CH$=fP?ql97%s;>4Vk2=yM_HBmj=hr^voH@I58o9@C^Iv&xRa^5sQO*Gzng=< zB(7MxxHyRN^18XX@wnaKv3IiI<-c|77B8OwuYdqI_y)JLJKV+S2{+vN>R%W6-*xVq zIh#0HIk;Ha!Ng1gZ_KY#Vp?1|OCcY-_rJuEOlUfda8ejYyFf36Lh zisL>NRkeCzW~+PG$_~sKxQC?REk5y|-~a8*zjypkOPzmP@(b_@{I}_UPW{>x=4|G4 z$KDRy(?#;%_4>QUaI%itddxGWoXFIOJz!w}i_wR`3p6P;P}m?M${TbkkG1msFarFJ>@PMkI&xilXB zufMLTqBOI`$>H&y2$H#ygV}y=A-iEgq;Vx4=Pn9jaFc2a>-vp%L1j{cfSB1A@7G`T zh4-((_0qIyEQgre$qIz+hAC+t?tPCsc_ikPyftpG)_Y|3B<#0l#LVGh1Uy;Lq$1>U zom_3QC;~fC*=s&Yz(sR=UT87dbtd}E^3B~_L(~2XYZrg(G`Vz&DRG4=M_q|yJMQcK zyju$eb;pS!M---cIztXj{@L3>lMLxcvLHf${U>!z{RUi$6#1PsbSk@aN(v5-{%w`qMoG zuBEi)syokig+O$3vyFHi8G{ERIbdyz zRV%d_F7rLIB_`YcxOonz0P}UrG47TEcw$plAugvRj2Z|%?;HU`j~BA(A7r+PF>o!y zZ}UD_vN)Bg#MpW@Ox$>;6KP@Hmt}PN+@;u7<(Mox1J9+>?WfyA7EI1lZ{(x1oZGh| zbkQ!^?yL1goyk7O7vEWql;zD2l~^p^uqS7;_S+fv?4C;=-Wo8pFB>vPrb!ZR2jlvq z>JO&m{%YfNAFva@vM+5|t$xYY7%!v|{&O6L+2 z(HkTfd8PZT_Z!umcoN$xtYnwcHDiIK}?zIYG#s$wXL_P zJ#q2d-m5M5yVysf)mfrBiu=w{O+xuSmn$u9OOoyua40Mpo~)^lXP;}RF>Zubksk3}+aFVU z!pz>)w}!2t3SZbM&)UxU6d8wlfC$mtiney1Skd&(?Ah~-TAnx?_--FrzR@K%yT{P) zHgVLYS@38~6Q#-i_9{n9&qNO?z3^ZiKOJ#W&`-xCEkj6L3{7hi{kb;$_y{}oCvPTv z7hciu3ZvJwdNnZqA}e$syrx>-m>(bR71=F>z_SFU-3NQO*GY<9dbehf_VM5mZM4%6 zc^rJn>G{``K{e&(cZk`pMEdgQx8p+@#G3NNta`3(>@O5FbIfCVr@wo!Odb)HWziRlS@rYe{$U`Yxxin_Q%k?=0wbmIb$&3q(C_76gsGOz| z%~`Pzhmq_Wi+EiF51m8Y_oid)U`gcK?$IR?=|lUJRq;}shi1aL!0k>(B)#|2M* z(-!iokgK6L8)|D$jt`0!5Sw4+k=sin&D-anZnUx{$Ci(Kv_FuXe;={9^3>s?m-qKT znhv)KFAEC;w=skxKB{`FD#Za~5B=&Aify=Liyh99)@^_I*laocONDQ~8-KSG{*-q{4CXb$&LoU|uwNe`|pr@$OuZ zUOlto1muXpm5k+!n~F~_)kluc8Gr4};V5?>Kwk` z)}K$KugJjf z0=dP#51-JlKI`lioKT_?-IutxnW&!PFcW9d1c`>i;B`l?RU{!+A|_3*E5@d2Oxd5J z!6UdN3eb%R@M%v+_xDrqW-^fQ;<_CVbaw4P{xr=wo65qq?F&cB4kKDr$Xb&6!uFF# z3o@kn{+bIc^ro%K&E#h%Mr*fFtMWdaM_OO%v>`{x?>ZLOXs^9E@Rh1JAhAte$fQ&PApY&(-zisDBcI zUCL^^V_@~x3UyeqQhU$=oYvwGJwqye=yRO$4r<^bN(3FgeXKZHXF~L%c=$YC{>arW zSrmq?rDYPM^xwi;VAHAe(n4b&b9!2Z5Q%884VrAgN-@P|iX&9&%^Qt0hMz+*Fg+`M zy_Fb4?-zkoL<}zB1}Y=4Mw!ANjZ57=Tby<-CI$RqeTfPqFi0c`g^QAe=k}(y^6of9 zte$z{1#8mti&jYV_r8#HxHYR%EIA2&nAq}7eU@q03)Mw1vyR$>Wt%YAGNILKQH+M^oSA=it&*BWV-&`#FS&V7Y20fK0OR75id;Y5xQd%r%rzV))UG&c2&|Xh!S#!y1mc ziL+8IJ^XXDTUB#iYCaU0s9q^1ge+#lB5(i;&vw`WZtM$oyUJlYN_%)`|2vWHe(p-b z@wpcDF%nqOOj6m!!>aewR)6i**Df%(+<*T`92WxlJ%zZGe!_f>`A;ZG~GA`(P-)-Hw(`qW`wIHvUyj%CczEXzKfKK&ou@BAoGn@pe z89Zb3+EnwT$itHzYd@T!XD93{b?g)w_SzX!uJblq(*1>Is$aO zZK4AUyG;YztBlTO=1kmB-id_`y?=bKz8!=v_L@tRB7wqC%f1HG>qE1n9TdlXLAhuq zt!IIz0&3557t&n;2y8~Lo({;p(RK6FX}ja&4bOsA*w|KI1E3V)flg}W4NlW-LuQzC zHT-ftov2xDLoc%+QhM{*oOq??CB420LJ`A)RzltVs`Qo8lW$NTdbO1m^a79mQAT(- znd^t@ruLp&oZ%WQS^if`U5+17ZQ2K&jD4A~hE<;qP&g4wsgp(ZKqbGA8r(??J{j8r zkwxvi=ZYJvHf_%GCzJCHwzII_XF{;u>>d?v4H>OLZ~xx3E|El&e$uM^ zC_NoM)I6Pta)xPS1bV^;+{H1}P&;%T--K9Lps*O|bPbX7_+QNw3g6UcLR zoj117u1k9Qve~HO>&o$;8y-ltI7Q_gdw3LBi^Hbp?F+q||Aw~LIHkj*aw*$?Zjn=* zDM$^3&{yTR=$?vYf4J;e;ardoOw?NMkwIu5Q@Vd*Wvbv{gNAI<6M>>sgs5;Gp9&_m_-Nx9+WS9n?lsL-omXZUsq&2zJnh; z;nmsMz5*LVJfw*&L~5NhiPzax?!lij2HIocnHj3e25ah8al`<*^76vku32Y~?p8i- zUeU|4Yrl_CLA_TLyot~Zr#ef0G>O0uVlv&k9N4t0u0z{@$U0*t(8AHOm*Lq#$Ez@T zmSx1B%JxOSBBkkG9T6(>*4|XaRgrZ5@6_CSrh=z?06zhb*$CjOQ|ENLdj7^!sXEWp zg|`_TMKS@W8&M=j*43|gYX|4pQ;j;An^R(C8qn;O&kVB>H_Hp4&H zKgk~5yg2ctYNfD?e{hpQ8MjB&3!T~&$z!fhI;ml8>4{4F`52n21A~c( zwGn2iCd2;xDHwAei53%tX(OLAd2Fz2zIkc*@>8x~U z*OQ~2kuO}dA1n6M3cR(Owes}hB)#_Ua?^=QBmxsvRG=b9rKr&;`CQ8NcWpdFQhfN5 zIz+{_gTHwy+xvx+i-{=Y&ybVbk6l+CRKplPu4k;_(r^(amWevL`P?DXDJJ~g-d zBB8L=l{*3xHlB~!4^>su@eE;M9zU{c53G-OM6f$tbz{2|Tbd{4*Cb3C4jB5_xol)cXXV7s9EdzX`Kq%7#nV4D zF!^Aa8?C9Q8NM}aQ!qp?KX#Mz**(fa$j>`QNCnhS>?1c=D{JujTBiDurslG;K zk?s7KESBGIr;oXgbh6Pxh3n$m$%=b!O#q-KQ^4`I@1ZZf_>8}I7jMgYx2{nJM}t3i zT>W@2X|ank#!F3kjAW}^dh9!n)ZjtSrB&QfpN^*Atz{0VvB~9!n5kXPsny;;H($y; zu}~49ycWPAZC|scRTa(jfeJVzQJ))!bh-$3LZ-JvdwbU66L^ivkIB8CioOVfEQ?uYRHPB4f#2MZN@sirD2 zU(GviqgypL0?5U_uP_0`7+eWJ`eO69kW~=h8h2~l5IPr{)E{Nrt7A;p_lP@pBvA?v z9jzeJ;v~{N9L@1g^YXOFiJah*q*l%RyAWOPz_;6(exEUU8dNM$=FJbc$5yMT&lZmg zY2VCtkXzVOo}hw+SRZdG&OYsxFb|{=Wo0O-t@D7spAd{rXb=bthLWJ&R+hU%pC$uT z8can>Cs;_Pw;G@eBbu+ul{v;7vZ|U}zvgmV9S-w$6MPgSzU7&>F$(Cq(JMs*m+u78 zhD2nz_Ul^2f#9-vWtp|^b^wdcf%2F7KP^~#d0vWgaQ-rpb)J5?aH5!7 z*~$?Ube^&wxGTs#YsisjRM*7WldAJnrg?g$ZKJLucH6X6XM-dHzn&a;wXtUo@+ore z4*2BbqqCHW+0^*dtnx?babCE z?;X-|YzoaI0%dY3$yxKKe3b3^ie8`dW>P4LkiP*5Mpo6tsgjk(+7sLMj>mWyDMcKPIL)mUX8S#qb9BmRjJUvrUa%a?eo7^<-<2{v7jlmRp8=4s_KmXBHd5G@t zxJ9y;xm*ZcdU>kyDYq(z8?>e&0QEoJpU-rafca#tD>oPLXHfcAk}Hzz%4mts=Gdh> zcX*qdk*6~0sWZDi#%YT~NDs(PdA6%5}hzCm?|@E$D1>hUHT zu|O9n00_Jn5-ck1)Ki{$TWRs=^Bm8dWpZ!pNffF2ByYMsm@r60#v4ZIfhczVu=C#a zmLA7_zsTb|x0^#5mL>#`YT55O`>^`^3><9{7hhBO320m11J`t2Xowoe>;@2^<9aAs z4)HF(lu3O9?<*gHS5?STy3Pmb!|2qMzsH`g=fSavZ@@D}lBF1f&YBMrN6pJ=!%Wd< zHjw@$I6~q~m^_s>-JSLVhp)mPl1RRc3J0iMbnXo(@W!Y*BuVC2->(nWL(4?p#+Rs3 zhFvoP*?e}(ua9RTmETn;O|5)TuP=(Z+H!sD6NFHpo5bG z2m-=E1@Ca+)zM2do3W+GAm)S1geS}E7fyA_`5w#xm8H=bE~aHyVcJTj`IOV zAF9uZE%NE7M_HuTvCh%4EA{LQ!#n^)Gv#>NU+wQ*@M)VSA%j`}fcW$<^vkB3e3V{2 z-op{LxrrSA!_L(z3+n^{Scsg^QE2w?8b}4a*yvk9`J2R{SzFO|bFq|~Iaavt)1+=dnDa&vR2*#79q?>I&LVxpaQUAT{=ET0@y; z`Nh)eP&L1|1il~>GkZoTt)H{S1y+^4fA<)>PUXsQm~VFc#Jc{dRi`;`Kr>$%HH&OD z>A#hQMCKQC8C*6SRQ6tdcw&{#_lZNvw;)@K?P^KihTmL|aKFr+)Ie#XWE_TBHMbr9v%)d!u zau(@uDwaVo*N1*IhMq0r0>nIa*{nA1@M5#4lv=X3=*lG`J0G9n2f%@4mg zcYgMut3CuoV3~>Uyn+|q+^A2n!S(HW;s5n*2S)&|#5*_r)wlnq0;RQZNM_n>GUfNY zpWi42*gb1(x-R~VBL3S9k3g3l#JW*2ApvrKO(TwU_}`J!f6ev(-Hg~Y9e8!EN5bdm z{@dcOwk;BX!5FQYN#MsV@y~Vs=T~?XNc8Bs58br<&yD`S4e&EW7lG|-ZHxH!he6^K z-me8cYOQNZxcvKFRj+`lyZ_m2>e|1f``?k@TV7yD>jnH4&;RM=Kb?*w21B{vc=6Vm z-@BVKMM7>Gb!gLZ@yb8n|7W-?w|$v&?mm=zK=AwguJ%5WL89}0TaGHtFH+x5Ou0w&d1$)#dh0!TU z)(;@(#A}!T-6Zh*9Pk5mB^Y&WHKT+M`=H-R0+p0GTSR{pmAXbu67@re1S9^v*ME+P zY381GGr2Zpm2d>{k_$vJa}owB{5~)|fBybGJU0s0Ji6djtLC-lN^B< zxHX9EE^fd4=h6E6NRs~L_@Qxy`PP+RSMPqIbpL5xT!^*@(pH_LmCl_&3ljoZ3=+gbzfcIB zkO0vo2VY#0TaI@OB&V#(%O|`K;us}7OkGB7b9YIq_pv$KVwqQu2I`K@&Pg4v{_y#7 z={Il0a*vraAQwbb{o){2Fb5IDo0v2Z70iHCf-p#7hdjKFx!B0v63=fE^d@jPHJH&F zr$*3Jc`+@44|zvI!y_2QsVz*z_#{PSHo3f@W;=clG+iX}&lML}`qgWse1R16w1|Q` zb%Jb|2_NvF{2=J#8?mpe(Jg%JN9uZfxS=9uXh2FtN*7tg^BCOOV>Z#P!*iv^qI)ae zCco%3KkfK?E(aWmf|Z1Ak2!oIb?# zBM(leQOD-E{yhEWdCPIYmsx^rkC@oe^Q)nJ3}UXY^)phKK=zs=hG79jGiJ@Y4w1hu zcH~39T#{lOA5b9oDTuW5)@%ZWhZ&`LcAA_48K!adC1*ad!2=5IJUz2$9s}#P7+!mn zc0rQE$6eEaT(Ej^jjw1%ytHz(xYOGhU`KOLG?(6)sPq9DK&jL8{Sw$LunRKS(K za*IuoO(InwrESZi)h7xi6w->{UWvCKOua*N1IU&{IJ`Cv&m}=(Z+Nk(2}yYo94x zYYCXjmxoJj>@b+mFDOjD$C70A*(q-{hcVd;8Y(xV@K-Q>EMKMIV*FFhUsCUM0^!$E z0+36LtTk!A$iU{RNbY^c3CFs`z|}gFJeMzy_>&Zm62hvNfQm!-eXs8UYSk$UzAiDB z5-^%}#t;*wT0ab&?~)VX(;?9WNkF4D;&A^vQm;LlyHkNR(R5-Vn8|d$}HOl9D+#GZg!__Vf- z6@$cB%7V#jzlDXYWYYPTa9JX%vyreXzXOq4R)%o~n6g-kB zXDj&CGfhQG_k)@2|EePg4Li(OmHQsia0-@x7g0|q{-lspmy!)9`!EL{bz8(F$pgzy zFK%gE=y9E+MI902Pgy!%=}(p(S${yKweLOd)XrTr&ja%Bt>QY$nfHZY zliBm0d6|fwUw66|S-)IBzy_-O@|m?!jzCmS<>eSR+tX#~8+_hG37a&X-I#k9HoOB3 z?K|Slt;DZ^*|`9Z(@c#^Gla{S*f4l)el40l66uyYsb&an1!IN>vL-nA|5R7O*1eKj zncF4IR5F&6a|nB-r|H5vgrr*3S1)KC&2WtLd1=Tf3v>n=V%yxdFxtWSX>fliq7Tyr z(t1Eh@|Kb2=4eJc3WO3hA^ zSK32|nyl`6>$F1V_7#7c(!_5rJDT-HCe86c9yQR_Kd1}zn`e3ASDkVE+~q({I(n|% zNC}^2HJNCpw!QX+8qZ?mVsNZFP18RLj8V=+*Gh>`J9~;q7u%M_6JoT4w6Em{VvXEH z#Cj|1NKw|P6ByB@?-M+(*?H~t6p>%2?SV)3F{nYna3yLzH z-hT)3*AW{#0SiZq6OGy0kH(q&s^yn~y4a@lFO6iOf~)9>r7w9o+Ia<74%k8hNL3Z- z8p-r0+;U#j(STnL!BF*oP%c*qNqx`3FQroj_6WOy`a;CJjC2aqY>y@2kU~il3cRvx zkV!q6lYI*SQ!eEzs)wi7?S~B)+#DgxmX;58b`W44xbt@y8=%o9ZP);EU7T%kd9%)Ml z1`I;WZyx;vaLB#dy_Yp7HA@c%&b9`!;$42y9L|OwkjRE=z)$bsidzp4cQEVrSJ+XdV|AVEGrX5v3 zNYYrFcO}F*6uQCQSFXIM3(3l)Hn%QxLsRb$SIhs8$@qKCnG0|bAIhnDl(y_pPray@ z^^zt8^FG7(wqJCAFU4sphdpHzSqb1_UB5jctzDM#;{j?*>1B<~2c^jQv8wVR04I)= zhj~IlYBYB5XlG)n;=yqQDG?c?Ezkm6#SDC0r+YkZ53rp84re7&=I*XHn~ToGnkbEw z*&V?sYMF#>V@X>+s1C-edy90WL5mL^^XY_bExRNS7AshHv&E(W1h9+d(lzex^f6AW z%QsJQ=}~ayds6i+nyJ=okm5RG3G^+avW zd~c?T(nqqZlyC-@FEVAXQpa=DEjH)Ax~kgc;Z$=!;Yt}?GrZJgUR~^ZjHh)P0V`=+ z-pe8g3H48rr0dt-AV6-Kf*p-lgXf?+C9Xm%eo3ceU9FOYE4F-?tcN>2@<>p?ID@Q&q7 zce1@(o~lZewP+^52}po8t_gSh7^hO7JFQ#12xMel0_jN(Sw%&XyWdW^-7j-`K;`1? z2?VDmvtwCmS3UFk#(EHyn{{H|&ok_Hldw)h>54Q5460_xetIeI>anO$oPO|mjxTsb z1rLA4_RNO3&;(w!B)kE1;jB;FlEiFaY}vO_N^t`4w_Zn^y(*m`DrFSm-j$KLTMi%l zaUJA>^zNzfY7)Quat)PzK|Y|FD6F}l|Ak&TP!*dedu_i!<}C-I=Ag?OD(k%zM;C-3 zTy*wIDkmg19>(to;>_BksfK7lVp$?i#l+02PE8p<5|u;=t(*ZapO>mhRtSRByFQ5X z@^$*hE~Fj>tfx^dKsIBj;&VyzX~no)Sz*x-aq*SPSifHaYv}|WoT1A#Fj36583j4d z^=CIl#ekOc0Tv*;(bjz?$&*9p8|EFcI*1r#CYBziv}dAL>CV$K3{>rt=u7B5fFuR3 z%Dv{RJKoPhni>ktyltB5StGo|Ri4to1%qeXyt9E?3to@CoeRXW80An;Oauf&s*2Ii z4@A6j-Z<2Tg=beGQBj9{N>QrAnMuo;ST@)b(n~k_%1}8E?+XqdknmPNu07tjIUxL8 zxRzl|PvTwz6xIt_3kxFdYzdlfDg&^-&Yb`*h6P-i!KeEWlYFbhJ7f}lbNjMF21GEG z?6(h;{l*ak1{Ms7v9$My30s@>QhLCkud{at3(&J5kjWz=j0^HTvqv#C zg1MDEMK798p!#8dtLpxxBqFcjP{1Kc3J5RnWQ!`KhMnftc8Ijq_?F_6em|<%prtK} zGiDL>rrm1Q9wDNs5hDe$X%$8wHN)S9-LD$2D|$LU zNzB&9h_}q_!jq{izWYJNub~71GSLkpLb@E6ay7HxW&2{qyE#*IvdcL zgwQDB67?PvqhEbCQ2*`_QW}#US(dslj7TX5pPudzGHAaZ60Q|43(;gYHOokz~;=bY10)4H9~rd5^QD2To~TvpFqy!+l(Cq?2#Ypyb-0n&qEi`)K_) z@5&yi<8)uFrA^4Ti{=mf-s1&aR)@iD`;SwR28j8WkGVqsFinLBK+Kngih0WZvQ^{$ zyr%}zWwLzKzi#8WbAzJ5$n={NYko6eaF_RhZj8D@`|6K|!+h;>)p-fV&+cDz^AG1f_Jb#MSaf-j>JLlBEDOd@S+8^H59j`mTt=OIo?2@R z2M(4X1izDT+YhIIbZObSQ)U zXgwFC>X^KDQ*r!o2f+B&ApI6T-&rE@+q4ft2^vLP==hDF>EdVu<Ira`Db?l zOHi{1cJn0xPzq3;ty5&&FdY|H{qf{z;v^17apXII{9qiY`x1pu1HKUn7_LvC4o+Cu zAQb~NsE;ZA4V*iLT+#X8LD>-;aFk5?`F!Izdcd^=@SuWT2ix4Q4GNWi>l2%?pD}|e zj(0Vm?@5oI`W8SYEYIj}dOHah+JPFcAu~X_UDp6&nrH1dZn*ma@^I+s;aan6V7@_B z{JT(54)`?C?!*GRy7K`iC<@K{47k)ND**9yYdlIT0dKt|?w@;8Sn?lF_&-CIh7#yf zn9e8g)NHD20DX1~DB^ngUcobHK~Ja5R@b@Za`0yaH$VyzmAgM)ElGkJ20L7phB(F< zaC;>NBs)VE$yes}?#XHm$0U&cdVSSJ!eWjV)WgbRwWxmK5nBqVLO4~M`WyufC~|}2 zL|sg<&TJ33jR<&Xy&!{9znXg-O$&-yF|!U7Eg&Nvh_Y*58Dh2pOsYAk!80E!Hgmni zjgWZ_ZNBXm`S{06Do$IsmPFTK_G!lyz(-q9Lal5I=!C2X{V)`Z9KwnVR$TmvG5v~W zwtR?#-d!!a>KdRMD6-2~$CXXFj&kNX19=jTH_RyZ7%dj1VF>Fo1KduR#t>DxgFjj8 zX<2`%;J(Jwaa0i%vjy%RhvYe3Tt0)9Hu7A6d?mH<3F#ugKR zPZ8z=<(Y3P=h9xS=cYNk1H9h}3Q>N{%zLyr0RH?HGHD|CE(l`Hvx@qzgBlT$n>7to z49N`@AkJxAGG3o*oxvr?dtH_?l;Vu*xx8f@u^1t4{}-dKaZv?cMAEZ=;PC_2R7 zEZ7xGz~e;&Se3&;ft@k8AI;F)51EA0GwaZ`(6vAu~VG8x-`Rx9WC(kZj=S zx0PJv^-RFZ(TDiq7?GjY{UpXG-~8Zj26Orc-0sT6PHc}ls~j-E_~d?D8(rMm;EFsR zh_Br}&=gOMg}=w~-?L}vL75#;E}g^y)t^9*Tzy1ReoR|uDM!^Z$c5;%P?tGEVDPi- zode28r2~&_XkdXu?-e3m-!3cc2PLGv1%`FvC7P88K+enNXR2b`I14^}mv=A=Bt2h>yK{W*aWlbj;mf*zrfK53AIeQgvollpd=BAtKH=(kWK-m;u(PKlEV)`*}3%Q zXTXD?1bq;WxD03kj)CGq6;7{yA}b%;1gwD-=WFkyEp0IsDq++IHK6jwX*8ko!yl|n zK1BeTW*07RD7mDv;kku13mf3hdC3!^FpculEb0TbQS|F<4(jQV@&30U=1}v82Y~JA z06~VS6bHFxV`M)dHu6aKKvZ9%lk$GGHP8d_GpKILsrgIEPuCTylp%DWJUPaz0AX+s z=peJNDAm8sG1Zuc0W6=Fx}D9+g5JJoIQX-Ec< zE`8#Giqw(m?EKA8spBUHkEHxlU*C>h9;+I$7BwJ)apP)-UH2Y4WamEFlEq7vs^yZg0Ysc-(xk6AOlmTS>%b1U5EKF>b;?7h#ASDuGvo2$J{ zK?^_evvF8r`{y%}Gy1kE^N(}Ws^ZrI%dAuVe5AtJ8non7Q!z_!F9vl<9)Z_4Bgd#y zGZk)@AQmA>N_d&9w6Jy_-Z{lk0%ZB;xpxpn}AR!T@_Qhwgvwton!Uz{aZC{1~ z;;F=l=Y}bCJKl>fDrJ|;8=j|m^rMAI&PesLqv6L5v)TbD$8nn9Qg6@u^R_->U{E&v z*2$^buR>$Nb^rs^a$zpp>c-r|H9I!G(45RKj(CH`ife3dgcqB6`#IJ#Db=MSs_3kq zAHb2jRvi-kb`PZG9aa<|1RRS{EHdlZVj)J9JuR^|l zVy$W6#GhD<1^F5e>g~CbrT?PbV)Cr+i_mEzS{hT2&E*~ewf42~7>7X1fy%OhdVas7 zDy)he+w zWS}DM>9|RkpV1UmPLz4>yt-L*ROVZ1HL&)4PbXK{6IoG^LC)S_|2Bi1#Zb|UN&@tvCrj{G50iRNGz1Grh%k*@Jk-f_ES@g}`y@#~dE~9480{a)Oppg^Dhcbt# z(4jwjit@qX^}c7@a}DiMvxwGdT%WHVR9W%mz(j1!du>~%LDa%l@wC-#Lk~}gE|?j) zT)oF+`Y#*k?>Y(POoHQSXdi7?&W9(?frb%wa5lpwKGA@#VdsZ9b~lMmMpcvhQE{ko zXU0X^r*2udB?T92SoT_-6q8c9!B=GaNg#KBG!yk@bhd>@HLeb=W+{<5C7)6@m4Ni5 zC*q@+3eUXEsRf^nvH?vnk&vz#LL*hJO|gp%L@`uzSjEFC=)E@A_n_X>6){+j#pJQ= z?U&r9U;ovI>WjsnU9&S4Zctcu|K*kh_~rh0$Y3 zN4P-YyhHl6Pa~uOOrRCG!LEmGE!ln1&zY-vH;e6t*|(@3BHvOYw#Qua-t7p_9@n+R;8J= z9I6CQ7tM%!m&YoAhr)-)1ni!Rcy3of^TqSpRF$tC<2HIw9Zh2;%HxdR__>pjX2ljs zg{xft(uTOg-^<_7oPGITd@R;^pdcRF0@cq|JB!qAoSL+>&T!-`6j}6S?QEBvg<_|S zqS!!?-%HY2qCufEhb`Os1>397kuvn6RX5+q4GbKqUaoLYSs<3QErKOmEfP!mS^|1= zN8%;P9SqNZl_>gfh!h>0_PrgzFEztn#b~eDqMl}0hPPHjGr%pb?xEAQtffkHfZ>qs zK&8uy6lvcbFjO7CH*jJkoXIX*K+Id6=7!Z|OkTPBR0TT|31WbHGXRaaLB(y$Sd&lJ z=>J6O8DypyY|4?YBP&bE_-pWV)E=J^D>dGJNvh=h!iPy3c8|oG0se_KK(MoC(OtuF z8)Kw$fP6e{{Lgt+tIuy=R1V4~M zhHdf3vy+)Q(1O}NaU9dBo@(8byJa`yMiQIbWRmK`;icv%@xf69EE5+#YQ0DX|Ac{{ zo>wJrNv;vPCFO|(ehm@dPiG!2^1wXQDv_(++*+R>>(;*&fM!~QQ=GZKgL!#L6|hY$bE6E3vRCUS(O+I!7ufn7fR?> zj06`iJv>d#+ClhJA7G8tem{^YzsWJ%*sqQBVI`es1l>6H@!0kd4lz5viPc z!JMR;VmdAZi}=KeI8>S$pHs-ocGO}f*~c?XZ0*U*Ya-g^hg zTh3wUV;!X$vQGD`GKMsw9DCx2L*91e0rbC$1ow#xno#_F5MUFw+ z3LUqRjgiMP8s5oZuM6VVaV3h;JKxaGN5Vi)Z4{pm6Z69U?*SFM^22^X*k)=!d@8g{d+<`Q-AePjKlmKpNr$4a__9UBc2_}))t4n-2En3 zog1z#Ki7Zjg)U9GP*__I0Hh zrS3x0JhVbSqWIdx=|w1uCTvajXZb%hh&=Ykmm)9MP%tkBv_oi%d*UT4?Uo8=?qcfvLJ z#UP(kcxFAHg&P}m<#|3}mZRea(i?eux>Ogn4r9JPX6eh9TkP6EDH;K~^^ZNV{6@A~ zKearsJ6pGdi)o|4qV3c=zB|%5GoihMs>`566-|Ed=y{YKKZSqZ=CtsSLBmZu)}fA7 z)v(8&blN4}J~4UvI(dC1xv@SxhKI!bKpBTKA8ib~LTjadBhYd~n8ZY{`&M6ln=BI} zgKtax+nrru;wKm^4d%n7icUhxE?L1I@*|+cv(xGdw$qGE#Y*pf>=Tr3OA1GNae78p zSa(mt0J#)3?U|0kxN?Tf4C};9hhSTt4@Xt{(rQU0ZYw%5JU3A3|3YmvbPz_q>okISQ}s~R4PufugVPWNSG}@ z2&Jj@#A@v!LG+zcP&~<=cv7{vmX@zIXuCPk_NN{|4vk{*&DILy!Mj6?WO6ef|Mle1 zp_r;Bu8K(b(@ZKnH=$*+{N{-2oAQIC6?WyLPZqkEG`TLeMg?9PG!e5@mrAcahjHj) z{}tQu8?S+u8Iigw^*^#bVk+}0bm$#KO8Cx3rDTs!`g-=R%^dFzTAMl*XnT{X zD>nMWCoQo~MUcrL`2N+@;j9ZnO(c8|`bOS`Ak3?6LW-SB=BxHsKj|N4A`wD!2bK-H zG*9p+R7+o^*r2(7$GYDi2`Vi z)02M%V*NgR|N2Q%4=!r?y@2OW`~mxcq&oDrXu|l`|MrahSJ@?}2;Bxwacu%d2ufBq z_<|FI%_aWWRDS)dC0sP6?rkHXzmowk2wJOsX77K!)L%Vh6enD?@W)kx8Gq@}7kQ!( zwfUdY`d?R1hKq*LGO-hCZ%~K9T~n8T$+Uw-hTxAvxM=&=8)k(5E)l+OHa5!@-+vB~ zf4wp`94@Noo=s4O{eSEx>i>Y|rWt~kBoGCw7N~bQuM)gH4cX9|p?wcE-E+v_dh3Z~ z7%72Nke9us`+r(neYLXKuENWQadR5xhfzt+Ux zcT19%oO&H)4b;0i=rqj1t7i^+=?mBW1QGo@l3`?#p7L!HAz)tKd@s=Vz#51G{+n{h7nfcDO{8+vzxbXW-z1aCAUm{jz~knf${+BRe1f=J>VMZ{-Ei3Y2V z)PUzaW>2DNRx@7#z0Ab}3in6RTfi1afxh;Fo!+-gAiPjoo$J35qLY2qBp1J;x32r8 z7w9wU=rlpDhJ}bvfNgUgGPV9>2enb_5(N6i@02`2Cf{W;>S>fUrdYwANbl&9~L_g$c1AKRV51XS-ItG+84&UHR)bwXr@I$Y@md| ztp@B#L{aHvD3M^#Fpc;$WjT{JCqCDPYhFuvmE*cRH3pfAyuM9=50ha%$qP(ure?-9c?LyX1RN zxSg_`V(pzI(q`DqTlZqi4FVnHXFIkhP`!xOw(cwg%?`T53*hE1O;;o zV%vy7dKk^j5eC;A!#SgG_74$DG?4FqRk#6<$MOByT#&~GVqg4_xwJ%jy!j}vRVQl&1^Q7JQ1y;(N`F>1aG2rL6M9K? z5v#^*FpE~Th!IbN;Gp}uF{}yi+Ey3>r=_O7C~PY4XeCY zMI0We<`Zr+hYj9%b|2Y`R!>b(u8A@-hPI5zJm`N5_u!^|nba8Xyg59Ey>zeu6s|v- zEU{})1qzlv+7xvdQ%X|c;78k#?2Rbl{qd*h2X-{m49Nlt95f^BU}VYhBs)Ln0hgN! zm9SUgrdcnO3!v>VGrboE(`X?Il&3Va4Yhz!ov|kl;Hb4Bi?A6IL@pF1La;XR;`uw%aJ%>(*@JA^Z^0tLvC`v-jxUeFbtr_WP(p`B?9LS1vD z1FT1HUE1?1{_fYusbIcv!Wjo)kO%@TAmh9?$0fEOQxxY?OqHT3Ql*Ar5$U^e zMS&Zi#(m*M@g%)ec*xMsMz}&E@`11TA2q2DWVCMKKdS}X^ZuDU7FxD+dI?W=o7;D7 zXFyBM3zFyJPs%I}8qD2DZeU50LOP_4@~oIjD|c?~J$T$=JdMG$t>^>K!k!&xyuBK7 z+hH^2McOj>Goax|Ad+%iQ&J{7#j7gIj2XgNkBhPJ&T=&j8Et;Uz-GDm4R=C$?C`-ok6~ z0X3a^ZvxsRg77$b#0&$WX@>OB(#kGmRUwV9R+0H$E??NYFM#4HK>y~uVCFG|&+0&$ zcSsX&@aCxoHpBA5GI%OyOO5Q(GV3)SA!?RS@{>@>$@Tuw*-y)H9=`l&iseFoQjebR zA9kL+-odBTYApzKaGM%C3&93X`D^fO zbu`0KHFrsZ=dh`z2-IhSwx5cN#&groWzt(OPjy9^y%u8J^Cv)u8^|h;^#7>}eOTzO z`qfNlJV4Z8knj4e1xb)=fv6e!_2Vn%gC48=Akvn$(S{e#e6eI&2T#G9;_+(r(q-7n zKO*1C)b+{C4;vn(tMrSCH@tS#8Gy%r9d;Z6UQp6nh^SRCQD;<`_>xj6!A772{n-VB z2qXma0F(IV?5hQ*?2O@rq1e|*zma8i=3@sW z*nVKmMkM;fwCIS}RUYeO$CB9XPVN*1fNhu!j%kkZOi62?cCLJRR^OTXPBySv-T5oo_rI`R9mtKcE*gcsx&Y67>p_FOcdmVjq;6?{mM!p0WoH3_TkFIu z5|Az7w4jbq5hO&orP@2af4&;*t+`N}jP}utyYDQcyg5K6*Vw-QtqFlT;{SiZ|NHOY|4@Ty zmTP-$E=TB=-hR>M1bLX2phSvqUqdvc$QBNU&cbzWs7n;4U!LE&67Na664i+}K#x4+ zn3!wfF%U?9%s06-V?)ErZ`Ijw9NIiC(m4Re21t!K^$PPBA3};^74$uO%UwINb$K0T z3f@M+7GI}qTxOqg48$j~-D#>!9dM0B*t(*DQG6TD4kwM!(7ioM@8iTMytV!P1PLtd z7f7Wu{rqO!1(4f6xvZAJf9=&SO~CoRJmiVga{Lw_UU3+fcRtW7cs{`3cU8|R+P3(y zvSGn>zp|A+>)CO{bv37NqIVVcq}WNYBM@-cAS(P;3EGE_qUaznv~TVx(aT{GT5}l2z9vs`0}uToE>c*3+I-d`tV*|yF{Wa zAY3D%=!^bGW`Nj~TjwA@{a5a3C_$~DG}T{Fy&RMlGnUq(?0B7Pqa}b^KO=F#DpP~i z)yN^~F~3*$R}Ep{plm?*3J$MNLyE(;8HSE+GR4t}1ABe5;S_)Gq}nOk112#+hxOSK z2AvEHU~GDfU^0R2j*L1EK}(3{dJ%Z9US5fRFt)4-g0Zhd`nKS$fzLAl;+&2_YUy2F z`p;s$W392)@K(7*%4DCNNQF{%1+g$!;B(}K zNGcfnNQyVq=w#q8EMK{x?Fbyf5F?_BU^MasMCa6*^9_)YlKd->z%xvPq4b%-Dy04L zK#X>=Dp#i)7_Wp!u$P(-%N{>mz6Is@^-pt%h-R*ISUTdyDMC++IWeFx48VowkkB7_ z8I4va=4wE^$z?ORrbJp^ND+eKmbbsc`H*2eiapftF`=ct4-m5Tn@5MuXL<`(-teoS z5ia4%ZRnU$HqYzzLJ{Qvp0ZD~>omHKoJvtKBm}m5X*yUv-5}|2hPvE*w~E-Z7C_Nx z(W9eD!&Cgyl18mA6KmOizs3NT)_Q-P88A4|3S8Q3n?F6}?O&%ty z6KK$b=UE+XP(ipg{~|MkH!0D1x-Bq&&1y0p7@sKysz zNM;H_)&F6p_>=hggINH&;&WCsuZ5+1k%SH(XiR|vbxdd7Qu@2*|j z+sdjdFkD7r3XvDh_Pe;#bZu^bf6shI@<#8fB;{o_tE6lS_52y?4@^Ho9^QMTXzTTa zI>T&lK_MAAPS=b4iRbRaYLXdG)O2N}OpizrrAX;YOOl1`gfrcf0sIWqv5iQ9!*xdytz&T|}4C_ar5 z_t0CJ`FQ$M$t}Tgm^yL_vW)oF*KUGC)&Bcene|d2PuiEse(RAFn^tMzzIBt!zL;#+IL)ib56^Ef$yLCZll$@FxB>=T}IK;HO7LNam za{f9aA6@&L-np^+C9y6?%q+#qGYHHbcMF#Z=qn z6WVu3bzuj`!qU`F!`Vg)-r@qymPN5E+fKv=kC72-$Tz#WSqZkDuwyb|adCG0?>~5; z0KAVGc$GAO!m2QG&PFN9-Vy^22M1;3#|q~>*=WdOZ2*cV8P0?g%dMy^)p+rCaOLPi zve22cXI%@Q1_Xow6jhLudn7BicjviC~DKAbkYPpO^q{biWWPD^=OQvz&>PN$`%B@PTO4$4YO{<<3In83xb%lj`t9{D0K!v z`yl&{WB+xzzkXBF2q5|b+gl8wi~c|V5s?Qg*9gxB!j&+8{{tE5tnmAOexp;d9qsKS zV3|!^&Cp1Ba{2P*M@^%RU1AmlyAbX~yO~T4EAOg9cDNz3vpm#*T{OjOdkY7t&rqa3 zh25xeX|hACZ=wd-W9y#K*e^|}KXdr<x6FmZdS^C zu(8jEL)Ksew9^mh0}nJZS1}(B!15`nma)fj*uH!Y&3RC_A69wJBjc#>BHU@VPu|h7 z@VQ2MO%DWcGV}9y#Xv71{!M*-l*iV;mhnF;mW()6@)fD>zJ2?6FjHDdfS1gU3EIU> zka65}84eIM9jx+5Z4_zHgJJ-jk{vN1rj9@;8JCP>qx>!lro4KJd60&9*4o^K?9P8K z`ul~5!;#A)dL$10;${mVL6ksI6soL3=g9<4L&hsYX|yUa7uz@v8oxAGhHAmR*t+OC z5Yr1adzm5~V9>&0#$_2o?KmvJ{>UWLlris3F6MZkgU0Iy+`>p-{>96kqaz%XLM0v7Ro{)Y8shkZ|u1Emo%^V|IFax{c5C=g)brzaf)XRb3^+Me0QcJR#q?9it{lhy)t!12fx6 zJ^|p4wT;aN8%h(H6`Eyl2R5`nfs7KB;E)i%x&hyDYk0D zzD%_5Hi6ZGqP&Q_z`3>*#R#Qd$1k-c@z?2%pl+1=Iz0T6L>H#b@IHN$mXh+^8dI}6 zF=6re(If1hy$2hBy8riDUz_n&*!lT)dB370n?NZ(4h{|;0kL>EGO+3r2M>=1jD%u^ zF=#>DRXP!zLHOWta^8j}yzsf3LycKmD~Dg_+f4 zwJed1?dSN@+wIBn=J+h=+q?tun+N{|j83jW5H#qbP}$JuIZJj!nWNeuW(S(sO-!T$ z>xILR$r=g+bG>U87U`m(IM;y3{E(#K_!O9tcrYM?!h$N?Eru{K93dly@keikqNk~ZcHTM`z!dH)ON7o5?0&!$2G`oC3BBYG zq$mGAE^a5RgH+;^zzFW=h$4XL$f)B18hroQK`{P|3odH!Eu%^3Q+$QsMmBLbSAs>c zA6%3x--3|iQq7$x_eGxF9WSS$?9%?{I5UN`uWnQXFC#f5OqBcPO~_o^{P9pR+4o0G z4fj6LB>1(l4+*<0B(Gbo@&DZX?18(!WLUS(w?qiu-Mh!M`-rKTxp`yY59-OzQ;n*; znS{PHN>-!YJ*#h3N?%J~4(3XhPjcmdvT8X&DBEt=ZV95?`$rzzMU*lR>!oVtXng$N zToh*esc>f-JV#~SmDr0X1bKfP$)|HuReX;X=Fj?RE&GS(gf zF|F|-8FNWYOf>!R?aS^(8&NVsM^D@S-lzEaN2)<8oQY4i_H8Vcx~XK`R`NSp z=~&*!anI#=*-?e=JX&0@+jnG|`D!JMsRt)D<=5f)xA3BlLE-G4D^A(4Vh_@6% z1olr#*7L}n%QYxFg)n^FeE`@dK{>wJjzA{po5CJgGF|D69D(5ROh!st1%)R{k>_jp zEWtu~fS#|RqU@qCFWw0zSfwi4tv5Q|AY33{MzQ*4gELbX&N>Q7hy#&%odIV_BVfM~ zkOhYz+r0x+*y(%-lQvD31t-e$Yu3QDu2^s?-hs0b2lKTYen2jP92`H*ofAN5X7hIVcfAl$I?%j z@eYXJsi>$))EvD5z&y9qu5z)<#mu@giTCMll|%W8x8E2r_j7;^`4G}IHUCO z2ZxyK`id+&t{{ULL+q3oj6FtwT&E|rF^*hCP55Sac53m4eS^B(ezKjpZ5F^dg(P5M z)8@zv0`-5RsdobS+da94xN9{;9dp3>1~J^KY^$m-3yH3Z=_&XlfZ!MMzZ=$KI6_O00N8;!_}>~w>EjeYPq-oyln(*C0Bu>pY*-} z*-}EV`@#q4vw-3QXY!hq7q3R=w+&rgGf?AK9s$~7rHTs~v>5c+CG_Y)gpQ#AMTJGKus>L92RC`Sc*d)(k*-3V@D z+SqUl8ph|#kbkKAaHSZvhPzdNkkH0kg*;g8CCUJdK=h=)GS|-z&|E+gJmw>iYlC%J z9DDbD_-zVo|6@Ajv!sDYlKi9GfE1aYMk}D^hi6nPNZNW-oo^f>05DK_2s#E5tKt5> zBh7BhGaohKJPDs=?6)g9_8c?Y$KPi80B(L$cWMIL6I`B;tN9!OxnAg*U*w9uEdQj$ zyzwrMR=O_Zvz^8iojhO*MdSx}#1DE9Iuog1N=p7ESJ2$U84WH-KY$SgCF#PBluWt*yH5 z<$3XR68f%)LjitCdK^4KO5jGm0>Bq8acqhZ<{<*@Dtm(X-a`cL9BK#>x0~V*5X20- zL3Bu?7VrCz(1ZOAFzu-716Kkc-}@dYJINuG?e*^(brIeHDgo{k(Uilt^Mr4s0m2vj#r=UcV52CB&_#B6UkA30P1{qL z(0yyjkbI@W*?IUnv@Js**+B{(l(V2dYn~KoYkhVPXcgE#6|Y}U1Tq5+nFO`Co-? ziY`*H14rHjd6g|Cpe=~pz6?S`cF>&h3bIe2*oA~X`meM{1C^`2v_-x11|^^n=+mCz zCrmL1ZH0DF>ZQ`szS1d4rHvEDC;$vP1>HQhdlg%&v=0w4g(DePzQ9Y!DJdy=_eV1j zAS2m;TB40-DTUkMGwt@h@Xt?9oFw^}498_qiV`kTrsL*@YV(EX!^)Mgh-pXSE@;6r zGc(ITpY!bD!-vaUOCXk@0fK5%U_>5NqhSVySpj*573Q>`ddAa@@M{=bAjVsoNd9~k z6jl+zR_*QWrqH??!yr@ZcxhUH+JQ?alvy!c&cGmMg70$H{f7?~L99Cp&BG8R;A0AW zLXAie=?dhk{py}{eZGMt&o~u#$pY)BG9(CmOVg0%nSj!!Anby6-Id#5KNa0l;B6{9Ec@~d^HX2CSJ`8gD|R? zms68FFfcG2I$;J&F4;1_Jl~#WAIi%XUGduhPDY`pU91vq`}bD=jjXQNuAdF6=4Fd< z(WB7Eh8fO{x^)ERtYcYz6$gB6P}{dC{=KW4S6`Es_GyOx@ad5P)veNw(mOX?K$g$U z$Ja?LO5bVGrY7^6X8!Ae)}=n!WuwlP%{GU@qx;uE$O%i znjjhoMR*z*aB~)DT>f!n#v@`-{@8O^`)wd2Zw*4Y%(UszhLXzCqbwneST zulFaoh2}n$yf;XjN5&Gr%=5}dHD-SJrm#I3DoIhrH`FMPH8adR3GK1j%f6f*AjTGq zzWHHMm_4p*GfPnotSZo{3VN}^WjvhD`OO2mXvA-A5y%Z*I0(KBkY+JzW&%xn{}R(kA?#UN@Xrf5-m9%Hf@` zA7@WwlCw&E?AW=aD*-$a7L-YvG?>kE^OJt9MM;kIF)9z6EWdX}7>Pip2QQCOnt&B5 z<#dQ=E>sSJXNTIIs@MDHM?jDJ-sv4scg=F#6bqg|n~bB*t1{?Hg_GV9o^9{x(-)$^ zEyX&XiEzI2;Qrs;$UbE!j zUB+!^Jq)o%bg4bCk5ISyO*`m8$C1vrr%j_uLB)rIV!-ioR9@nj=a^fuxC~9f9BHhX zeEyC?*1ML9tP!QSCkzgh2B_F9RWXYsBaEh?VwFRpP&zt=IOqQ=8h%ERM)p)WhDPM( zr6fgGDnj;r^P1+`^pn=*BtA)D*QNA{LTSUd?1FXVxFxz{n5pEv;1DPw>T#Z&?LA`I zLFVNX6?6K2sHWg+I}aB>W=cnx4XF?BgX7sfIa$%k31-7igKf*B$#o(P?P^wt#=kQ> zS9$rvr9;n);(wK1&hrEP9F2Adaa$v4-1vtpY5PBTfpn3Ij_zhEzus!ME$|XDviBxW zebY04AIC{gW_U|0)N*22RSKrrsjFXi`7u!+$0Ls&ReUJCb2TX;t7&C^kQ)e2{ZpEepR>cRu;sx1V}okL=kO@g?{w?R$#>tq}iu9e$EpEXj#JuP0|rKT7^ z2{XZYYLKpqP)>DuFC;9#+=gp4!a?4=1)C8!oIU0eEMDXg4Q%u%b^e+%XQyTGuXqy+ z{|4N-ofU+)G}Uc9%!dbZpz4!9ZF^nYo)m*J`#O%+-1i-S*Yz%ZhTB%~aFFx6rkU`IcIYo+%7-w0YZ`%M_I8uz?m#g`MPO`iZZ(sxE7Ho#z*e{s$F)gG(&KQ{JZUFT$ufXz-6>%Bo% z3hk$xJ{*Q==Z^Xy!wj^Iyf!h5tw@I*7~mdaHu@8jU*|#YP$ITLq6^}IaCpo=%{m6; zfQ`YGqcWFeu`fcUhC#$Bd!m7zQ#et{Ycvm;f^66=A%;z(0&F6!%nuWUNG z9B{_b8on|dRJ|lPy%}@5Y^fGL#*!y^J+RQXiOzYTg`D*F?-PqLLj#3>e`AFKmqWH! z<)w>;x0F7?J8R-Fx+Q2zz>3w7bZ;Ndb9;R-nv(sf4+rD1c>Mt6G})`I9qW))ZI#|} zir)sO08f>0oyII*Yt*2Gun{A(wk@LX2wMaik^I7iToify@@DK9i22C+D|pf8)|O z@LtszO71Zs{AbaUK6s=^I7m3UBCSfQt}y-m#z9V68Z(jjHRW5%<#-fRH0TX>Pd;6TpjCxga$y*7qR5I*CPo6z&D7So+;;irw*qBwQmV;%T54 zc1+)dmTgf85Ep%KXQ&}TQ2R@%{Z4To>qYN-2XKg9uG{oUVBksxnOn`_+blFcMnY7Z zT@A`3-GQu=B2f4dsk|z>H7H)fC4NE<7+jUddv^$*p+04G+T8o#9+&ZE69&Eb=6!=d$i z75?WZKal>6{%Q_B7jrAlU_5{A-kUdX?iPUrhg6z`z^WjIr_re4e^yojmePj3BnFCV zU~EyyQH8}~iBg(Xv6#8fLT%$&(5fgk$UQC=QQR|)C{jSH8uaMVqvOWbnA^~-mWLfq zugI#vD8jFHCnKs5gGeEe+7>FWW8a{EZwyk1Gl&-wLaS@H$kwdAo%=Bnph0l*Afq#RK7IRk8v-MrI?nXAB^e!poroDx zcrRNedDsn9>S}0e&K5)S9gDEc&~lm)-igz}qk=+oDuFyW>2%O6H?+ozF!S z(evq=LDXR?{>1huw^tDG1$t>SIlTUB9r0UdpnZa9{MIX1TVHwak%_4<=Ed;*{PPYBAQ+@Ucy~nKt*$1l{0&6nAt5ZPQN@4n z;!z%(N#ki?om%U-A;!eWXdCx>Jr ztoo68JmOw|ZgPkP2t~;!r473~B2_vuMo)_ejnPU&DtMV6t4wz!o(|?4Y0q#%1|Gb{ zv|9SnOTzQkBtCzj#(p8oPk71_`h-;U^j3qHdhm$y#w8b?tCzQ89Rq1QJd3<;{v*sV z$eKsmS#B*H@E)x#1E7k$Q3!xcAgPzHv)#JOm%u|FO6{Eh*-ut+fl)YVHkK_gKe0hd zd_e}%;n1B{ID~|5Ao|mc)i|S4^A>tQm#Xe@O}5xk1CgfB-`+|92^Io~#e9EgcF?sR z{c7ufls_UuX=K8X(9PM6cXPfOVQ$M0mXb?@;-ruJI%1(S|k_Bao zcPOoO^3^L>9*9DCTWV_$8Lz{s>1SNKBs|s}9VXmaZesai@Cc%z$2`V&)eS;xz%CFI zaDk$kb?2rgDNjlE1l8oW7JtMj?R&t{3$g2x1sy#(CsWeo^BHDHS>X-h9L?^g%SQ2l+~n>UYC?sR@V0K%uD=66in zh;bGN)q%rh>}aS7(~fh}#}LKp!(m)KbhE~oyP*$cZj}&lk($Ae{~(m}L5B>jB^A!K zD{nu3osF>M$h)13l3GgJD3x~VA?ATW_mZ@=-WQ11J?r)3H51NbyB2co?5$3o#^F4K zclI?C?juhj246RTk#df$Pm}RFr`ChF4~O~VhEqt(3f2)*DW6lCp8_YJ7y~O z?bRN8NKADV41$EyXfM~=o^-C9RsJHiY4G(40oE3<)|u>-FlJ_Xiifck!AS>qd}sxn zq#CjA+V0Ap>h^M=``&?c90h$CR}1b;yMvw^N9gES5HKtYB-Vv#rO7C5_@8JZnnrD` zR$`~G0-LI^q_YpN=;@OUD7O)|v=&Z?cw{c$ig<|#wa==?*$l{grQ88ez={LzO1S0| zj~xJo)s{#Kf^i>O_LmnSEons54R%mU#(=P>D61;n`2l;?2ohE(hQVP->EVR@_WRLiCH+WA_S-%TCr#Um;cJnbXl5hao%#YxY ziop~P?khXRuA#KZQwk=)lNHYME9=To6d*$F^ua}d#1Y77q;XJ#aUu!#&+yLK#v+d0 zhmK!VbG#f8zCo<(ir)%ORFN;d5^Ndk{C!z5fLM1x;rI^hBxy+ni~Ub=wmVa-eR}n- zqf}I1)#pV&SUZv@h9mY(OlAz&Ycw@9E_?OghP}KT}C!wlJ&xT z;`_?G->++m!HBI4BYe5@kwAiAkSq$71uPrs51?>^;eZvMRlO7i&A%;<4WLy=zz=?5 zb`HO46n`=(FM8rp2Ar>tR8%`j#`h;pY=ZrW9cq#g=&Q|1R$#D%Jw2ZfG^M6yl+flmjOCCtFo_EP3wx zx()&*NQzFv8&X|Z(m|!A7uTD>(65THephaMJT>zly!3mAs$qsB8-Y5y2MmR7T)*CY zeZK6)Cd8haL33H7$O`RX3)9tboTYKm>uo!M45S>~MOqSUMzpSkdM{*r0R1G_Pl+Dd z3BvB(Q-z*cJcky6PeDeExE~Wd4#yEF!6jd%LC;K;mTl)<1eKdI^vpg~k-gtpQIesC zG@)n4vOnzi=l}ha_gS@TQr(}Xsmx~Q&ODa5Bj27^wr5t%<;0H18II!X)MONQhb z`Rl3!L?T9((}ts~k*Fqa3YML?1q>hhP`u^)mF-C6h6_k~BVJpw(}DylR!UYISU$D1 zV_U!9|L>njkfF{f|IfrbHhox?`Jke=XEn%kC2?8U=Htns+geQDVE-Z^R2gjk`x3u@ zB0)5Hm+A(KGdOukw;K!NikGmJMPn8R^O6aw^raBdpjr@${h=Bkf$xu89#-MQd}3Xp z`-ud8Uri3`525?a4UH$MTXue9z)rHZNp-gb3Cay;dx;!kZh9VC=ze$&##-uda<@^i zH)c3kQaR7~m>M{YXEAXRS`FVg)lT_jujy8^{+LvBelFoB`$fruO}=YXQtGj zSoC)Er}IH`&h8VO)wY^VokgDZNgLz#R|LXz9t@m})$2UJT)oyWED{Myl`V&#QT|hd zmp#?R-&Dz(Yrkc1iVu?5+GMDh%l(x3j^VX_m=IZ`&t~xsbN+7MXpi-#RAod( z6-91r=SNnCJluIKN=hnR#&)GUm1eu1>~?Q`lgzGB;_C8D)tW@tYkPRMz06G6VXjBj zHh6!=dV@}HI z5?VaoqeLr@+FZI+z}MrUO;s)da6rk*NyN<6fD?}i^jveF*A;RQSFYNe^Ko}(Lj#wL zTkBoUGyQq3NnZY^YWY&t%Rt9w`giF1QJypik-znP_1)o@^T$V*9lI@ZRGnjs?M#Y= z#qJFIJDG0}6+CUfSu5~tk)W(s?j1u=3KOQ8Vcl#r{Ef|E3CJU!Rf{s89-D&!aP$2^ z3q7*Y&&!wml^%P#<3CpOvq=wZTl;?;^gOS7!qX(}7rIX}+SV5T?AksoN>G2qe7-^0 zW#x(E#^ShmwJk7<<1bUs)SD_RFQErKiUY)EzvZS$guEQji!#^W-eSn0I&9Vb8AMs7 zF4}Gx>SZw(UvnF;rtSn(l&md8%yw2^rt(zY@#eV%hT_C;!_|BA3pZ6)1;ZtltSrip zZ=1(t|JbwdL>j;Yr8VbZ;(n>6sFo3EqosxX`4QwP^Cy?dh@FBv8(ZSFZz z(ljvtKANz*;V!s*TwF&cboM(OH#N(_q*xp2jt;*ou-ELr{cO^&yRddzS*I}f=FZj% zS*W?U27~G5m}>Os!;wOp!L8UkIVp85VaoViv#>iYwkuwrQj439Zm_?MAI|X8J^kA8 zek6Jglg{#9%soq}bJB0n-PuT>#pYIEgpC{)(jl+$n-O>!)DW{;rcZXY*=FLI4lp>&#?d%z*amR z`wyL{VD&BEa@Kp{{K@9f6+-k!BZ&eUJ9->l^ktfNp>sy;M11vYM*fj56X#ycmJf&R zw--HyQaS6@v!~43=c6Wb2aQo1@j;x-sk&(1cJ`lN(Tmo8Z#_%T^k1>P(DR+(5nUpg zL5@4c78*92hskHwc6XAd&5__TIcYXBATlktt+Jf#-((hFZ3Gf~$0uJJxmBK!YT)NH z*$wr33iIL%W(F7PGf%JJvtzrJvl?nI0$Eyr0%y#^=HBdckY?HiA9kQ1?sYm zdCzmJMOo7sLl+fF;k4KuBQ3+cPC8=v+va-3VNyjF8Pl`5A83Q z4+@ii{NU;(qpf;kt(ARwvFDy`xBCyZPxWuB1nrF<{L-l^;?zh(hL%uFWK`PCHp(1%t@~$;OWD?+8DR^Tn&a{B zr@ib>&U&I-3f->P_bhxINRG!pApLz9{_~ThC0zp=ivi8OGx(Gys)OOAe*3mM!>-hQ z$vt~Q!{Fx2+PsPfp4!KsNyY#3OTWRco@Ac2i7@mA@b zD;3#6S5MjtGb?w`ZAfixOH{EZ#!V6sU9lb`av{e#7OaASc|-w4N$2*yYySrV%(7&{ zRT6uMQU}$@3IJmY-1Yc@vy(la>(+1t#od%KL@!QqeH0cs`}WX$qbio)V#-M9HV6OP z*fvT6C}r1f#i8!>+qxHd`h+(==1c<*SR!i*(NOC*xo->Hbu&z?tXxQcNuZ)c7;yVD z=L?4g0if`J=;j+W|TIvx9B-E)&N_msgQmN$VySOZoDLn}vl%oL9?vHKV9;La#-3aJS)> zf~<)d_>Z$2!yx>%Z!QzOSZi(S z_AqqYAbg}#aUs6RGT4(-(+VAk)eEz0ATPdzE5c}-nr_CoWQ;rwwx7fqs3=A}p=nf{ zWjm~KF2+~}Bm9RPI+S!b#fuG^aUpBt63=ZARS=(qYhD%$PAsU2H1|9PtF z<<*{x)4j3@XZDA7qO#6-@ecfvj+9_QlAX|4p_4UGwmi^tV{sm6DbC{@!_tET-*i!$jhi) K&XvCA^S=PiCi?~e From a602e9e9b40ec1b177bb1db08867cb8b00974b78 Mon Sep 17 00:00:00 2001 From: Sarita Iyer <66540150+saritai@users.noreply.github.com> Date: Fri, 9 Jun 2023 11:31:14 -0400 Subject: [PATCH 067/364] fix format --- .../running-codeql-queries-at-scale-with-mrva.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst index 6d3201ef45a..4a312834ba0 100644 --- a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst +++ b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst @@ -158,7 +158,7 @@ Using code search to add repositories to a custom list You can use code search directly in the CodeQL extension to add a subset of repositories from GitHub.com to a custom list. Note that this feature uses the legacy code search via the code search API. For more information on the syntax to use, see "`Searching code (legacy) `__." -For example, to add all repositories in the `rails` organization on GitHub, you can search `org:rails`. +For example, to add all repositories in the ``rails`` organization on GitHub, you can search ```org:rails``. Custom lists can contain a maximum of 1000 repositories, so at most only the first 1000 repositories returned from your search will be added to your list. From 427f2a488c2ca29ea01e8e664ac730ad4cbaa2e5 Mon Sep 17 00:00:00 2001 From: Sarita Iyer <66540150+saritai@users.noreply.github.com> Date: Fri, 9 Jun 2023 11:31:27 -0400 Subject: [PATCH 068/364] fix --- .../running-codeql-queries-at-scale-with-mrva.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst index 4a312834ba0..3f508ed95c5 100644 --- a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst +++ b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst @@ -158,7 +158,7 @@ Using code search to add repositories to a custom list You can use code search directly in the CodeQL extension to add a subset of repositories from GitHub.com to a custom list. Note that this feature uses the legacy code search via the code search API. For more information on the syntax to use, see "`Searching code (legacy) `__." -For example, to add all repositories in the ``rails`` organization on GitHub, you can search ```org:rails``. +For example, to add all repositories in the ``rails`` organization on GitHub, you can search ``org:rails``. Custom lists can contain a maximum of 1000 repositories, so at most only the first 1000 repositories returned from your search will be added to your list. From d81ba80406d6dadcb026be10ce07cec7d99ceec4 Mon Sep 17 00:00:00 2001 From: Sarita Iyer <66540150+saritai@users.noreply.github.com> Date: Fri, 9 Jun 2023 14:27:26 -0400 Subject: [PATCH 069/364] Update docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst Co-authored-by: Felicity Chapman --- .../running-codeql-queries-at-scale-with-mrva.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst index 3f508ed95c5..fd34e389d74 100644 --- a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst +++ b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst @@ -171,7 +171,7 @@ Custom lists can contain a maximum of 1000 repositories, so at most only the fir .. image:: ../images/codeql-for-visual-studio-code/variant-analysis-code-search-language.png :alt: Screenshot of the search bar for using code search to add repositories to a custom list. The search bar asks you to choose a language for your search and has a dropdown list of languages to choose from. -#. Type the search query that you want to use and press **Enter**. +#. In the search bar, type the search query that you want to use and press **Enter**. #. You can view the progress of your search in the bottom right corner of the application in a box with the text "Searching for repositories...". If you click **Cancel**, no repositories will be added to your list. From 9abe3e3da464c3f65f7641e31b2e1a7a06163ac9 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Fri, 9 Jun 2023 14:35:37 -0400 Subject: [PATCH 070/364] Shared: use a module as input to 'KindValidation' --- .../code/csharp/dataflow/ExternalFlow.qll | 17 +++++------ go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 17 ++++------- .../code/java/dataflow/ExternalFlow.qll | 17 +++++------ .../data/internal/ApiGraphModels.qll | 17 ++++------- .../data/internal/ApiGraphModels.qll | 17 ++++------- .../data/internal/ApiGraphModels.qll | 17 ++++------- shared/mad/codeql/mad/ModelValidation.qll | 29 ++++++++++++------- .../codeql/swift/dataflow/ExternalFlow.qll | 17 ++++------- 8 files changed, 63 insertions(+), 85 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index ae1c928b92c..501b140b886 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -205,20 +205,17 @@ module ModelValidation { ) } - /** Holds if a summary model exists for the given `kind`. */ - private predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } + private module KindValConfig implements SharedModelVal::KindValidationConfigSig { + predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } - /** Holds if a sink model exists for the given `kind`. */ - private predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } + predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } - /** Holds if a source model exists for the given `kind`. */ - private predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } + predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } - /** Holds if a neutral model exists for the given `kind`. */ - private predicate neutralKind(string kind) { neutralModel(_, _, _, _, kind, _) } + predicate neutralKind(string kind) { neutralModel(_, _, _, _, kind, _) } + } - private module KindVal = - SharedModelVal::KindValidation; + private module KindVal = SharedModelVal::KindValidation; private string getInvalidModelSignature() { exists( diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 448196fb1a0..4306471893a 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -189,20 +189,15 @@ module ModelValidation { ) } - /** Holds if a summary model exists for the given `kind`. */ - private predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } + private module KindValConfig implements SharedModelVal::KindValidationConfigSig { + predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } - /** Holds if a sink model exists for the given `kind`. */ - private predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } + predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } - /** Holds if a source model exists for the given `kind`. */ - private predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } + predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } + } - /** Holds if a neutral model exists for the given `kind`. */ - private predicate neutralKind(string kind) { none() } - - private module KindVal = - SharedModelVal::KindValidation; + private module KindVal = SharedModelVal::KindValidation; private string getInvalidModelSignature() { exists( diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index b0a5b702fa0..c04126d5f7f 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -266,20 +266,17 @@ module ModelValidation { ) } - /** Holds if a summary model exists for the given `kind`. */ - private predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } + private module KindValConfig implements SharedModelVal::KindValidationConfigSig { + predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } - /** Holds if a sink model exists for the given `kind`. */ - private predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } + predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } - /** Holds if a source model exists for the given `kind`. */ - private predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } + predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } - /** Holds if a neutral model exists for the given `kind`. */ - private predicate neutralKind(string kind) { neutralModel(_, _, _, _, kind, _) } + predicate neutralKind(string kind) { neutralModel(_, _, _, _, kind, _) } + } - private module KindVal = - SharedModelVal::KindValidation; + private module KindVal = SharedModelVal::KindValidation; private string getInvalidModelSignature() { exists( diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index f3474d452f4..2b765765e99 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -655,20 +655,15 @@ module ModelOutput { import Specific::ModelOutputSpecific private import codeql.mad.ModelValidation as SharedModelVal - /** Holds if a summary model exists for the given `kind`. */ - private predicate summaryKind(string kind) { summaryModel(_, _, _, _, kind) } + private module KindValConfig implements SharedModelVal::KindValidationConfigSig { + predicate summaryKind(string kind) { summaryModel(_, _, _, _, kind) } - /** Holds if a sink model exists for the given `kind`. */ - private predicate sinkKind(string kind) { sinkModel(_, _, kind) } + predicate sinkKind(string kind) { sinkModel(_, _, kind) } - /** Holds if a source model exists for the given `kind`. */ - private predicate sourceKind(string kind) { sourceModel(_, _, kind) } + predicate sourceKind(string kind) { sourceModel(_, _, kind) } + } - /** Holds if a neutral model exists for the given `kind`. */ - private predicate neutralKind(string kind) { none() } - - private module KindVal = - SharedModelVal::KindValidation; + private module KindVal = SharedModelVal::KindValidation; /** * Gets an error message relating to an invalid CSV row in a model. diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index f3474d452f4..2b765765e99 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -655,20 +655,15 @@ module ModelOutput { import Specific::ModelOutputSpecific private import codeql.mad.ModelValidation as SharedModelVal - /** Holds if a summary model exists for the given `kind`. */ - private predicate summaryKind(string kind) { summaryModel(_, _, _, _, kind) } + private module KindValConfig implements SharedModelVal::KindValidationConfigSig { + predicate summaryKind(string kind) { summaryModel(_, _, _, _, kind) } - /** Holds if a sink model exists for the given `kind`. */ - private predicate sinkKind(string kind) { sinkModel(_, _, kind) } + predicate sinkKind(string kind) { sinkModel(_, _, kind) } - /** Holds if a source model exists for the given `kind`. */ - private predicate sourceKind(string kind) { sourceModel(_, _, kind) } + predicate sourceKind(string kind) { sourceModel(_, _, kind) } + } - /** Holds if a neutral model exists for the given `kind`. */ - private predicate neutralKind(string kind) { none() } - - private module KindVal = - SharedModelVal::KindValidation; + private module KindVal = SharedModelVal::KindValidation; /** * Gets an error message relating to an invalid CSV row in a model. diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index f3474d452f4..2b765765e99 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -655,20 +655,15 @@ module ModelOutput { import Specific::ModelOutputSpecific private import codeql.mad.ModelValidation as SharedModelVal - /** Holds if a summary model exists for the given `kind`. */ - private predicate summaryKind(string kind) { summaryModel(_, _, _, _, kind) } + private module KindValConfig implements SharedModelVal::KindValidationConfigSig { + predicate summaryKind(string kind) { summaryModel(_, _, _, _, kind) } - /** Holds if a sink model exists for the given `kind`. */ - private predicate sinkKind(string kind) { sinkModel(_, _, kind) } + predicate sinkKind(string kind) { sinkModel(_, _, kind) } - /** Holds if a source model exists for the given `kind`. */ - private predicate sourceKind(string kind) { sourceModel(_, _, kind) } + predicate sourceKind(string kind) { sourceModel(_, _, kind) } + } - /** Holds if a neutral model exists for the given `kind`. */ - private predicate neutralKind(string kind) { none() } - - private module KindVal = - SharedModelVal::KindValidation; + private module KindVal = SharedModelVal::KindValidation; /** * Gets an error message relating to an invalid CSV row in a model. diff --git a/shared/mad/codeql/mad/ModelValidation.qll b/shared/mad/codeql/mad/ModelValidation.qll index 0486a4b07a2..d5108c2eeec 100644 --- a/shared/mad/codeql/mad/ModelValidation.qll +++ b/shared/mad/codeql/mad/ModelValidation.qll @@ -2,14 +2,23 @@ * Provides classes and predicates related to validating models-as-data rows. */ -/** Holds if a model exists for the given `kind`. */ -signature predicate modelKindSig(string kind); +/** Provides predicates for determining if a model exists for a given `kind`. */ +signature module KindValidationConfigSig { + /** Holds if a summary model exists for the given `kind`. */ + predicate summaryKind(string kind); + + /** Holds if a sink model exists for the given `kind`. */ + predicate sinkKind(string kind); + + /** Holds if a source model exists for the given `kind`. */ + predicate sourceKind(string kind); + + /** Holds if a neutral model exists for the given `kind`. */ + default predicate neutralKind(string kind) { none() } +} /** Provides validation for models-as-data summary, sink, source, and neutral kinds. */ -module KindValidation< - modelKindSig/1 summaryKind, modelKindSig/1 sinkKind, modelKindSig/1 sourceKind, - modelKindSig/1 neutralKind> -{ +module KindValidation { /** A valid models-as-data sink kind. */ private class ValidSinkKind extends string { bindingset[this] @@ -150,12 +159,12 @@ module KindValidation< /** Gets an error message relating to an invalid kind in a model. */ string getInvalidModelKind() { - exists(string kind | summaryKind(kind) | + exists(string kind | Config::summaryKind(kind) | not kind instanceof ValidSummaryKind and result = "Invalid kind \"" + kind + "\" in summary model." ) or - exists(string kind, string msg | sinkKind(kind) | + exists(string kind, string msg | Config::sinkKind(kind) | not kind instanceof ValidSinkKind and msg = "Invalid kind \"" + kind + "\" in sink model." and // The part of this message that refers to outdated sink kinds can be deleted after June 1st, 2024. @@ -164,12 +173,12 @@ module KindValidation< else result = msg ) or - exists(string kind | sourceKind(kind) | + exists(string kind | Config::sourceKind(kind) | not kind instanceof ValidSourceKind and result = "Invalid kind \"" + kind + "\" in source model." ) or - exists(string kind | neutralKind(kind) | + exists(string kind | Config::neutralKind(kind) | not kind instanceof ValidNeutralKind and result = "Invalid kind \"" + kind + "\" in neutral model." ) diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index d55563604c6..ba680b1b138 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -264,20 +264,15 @@ module CsvValidation { ) } - /** Holds if a summary model exists for the given `kind`. */ - private predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } + private module KindValConfig implements SharedModelVal::KindValidationConfigSig { + predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) } - /** Holds if a sink model exists for the given `kind`. */ - private predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } + predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) } - /** Holds if a source model exists for the given `kind`. */ - private predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } + predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) } + } - /** Holds if a neutral model exists for the given `kind`. */ - private predicate neutralKind(string kind) { none() } - - private module KindVal = - SharedModelVal::KindValidation; + private module KindVal = SharedModelVal::KindValidation; private string getInvalidModelSubtype() { exists(string pred, string row | From 52acf5e8bea8d7e0ddc744ead0bc9dd5a3ec2d88 Mon Sep 17 00:00:00 2001 From: Sarita Iyer <66540150+saritai@users.noreply.github.com> Date: Fri, 9 Jun 2023 16:08:30 -0400 Subject: [PATCH 071/364] updates based on feedback --- ...nning-codeql-queries-at-scale-with-mrva.rst | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst index fd34e389d74..f225b3e8097 100644 --- a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst +++ b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst @@ -153,10 +153,16 @@ For example, if you want to continue analyzing a set of repositories that had re You can then insert the ``new-repo-list`` of repositories into your list of custom repository lists for easy access in the Variant Analysis Repositories panel. -Using code search to add repositories to a custom list +Using GitHub code search to add repositories to a custom list ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can use code search directly in the CodeQL extension to add a subset of repositories from GitHub.com to a custom list. Note that this feature uses the legacy code search via the code search API. For more information on the syntax to use, see "`Searching code (legacy) `__." +You can use code search directly in the CodeQL extension to add a subset of repositories from GitHub.com to a custom list. + +.. pull-quote:: + + Note + + This feature uses the legacy code search via the code search API. For more information on the syntax to use, see "`Searching code (legacy) `__." For example, to add all repositories in the ``rails`` organization on GitHub, you can search ``org:rails``. @@ -166,18 +172,16 @@ Custom lists can contain a maximum of 1000 repositories, so at most only the fir #. Right-click on the list you have chosen and then click **Add repositories with GitHub Code Search**. -#. In the search bar, select a language for your search from the choices in the dropdown. +#. In the pop-up that appears at the top of the application, under the search bar, select a language for your search from the choices in the dropdown. .. image:: ../images/codeql-for-visual-studio-code/variant-analysis-code-search-language.png :alt: Screenshot of the search bar for using code search to add repositories to a custom list. The search bar asks you to choose a language for your search and has a dropdown list of languages to choose from. #. In the search bar, type the search query that you want to use and press **Enter**. -#. You can view the progress of your search in the bottom right corner of the application in a box with the text "Searching for repositories...". If you click **Cancel**, no repositories will be added to your list. +You can view the progress of your search in the bottom right corner of the application in a box with the text "Searching for repositories...". If you click **Cancel**, no repositories will be added to your list. Once complete, you will see the resulting repositories appear in the dropdown under your custom list in the Variant Analysis Repositories panel. -#. Once complete, you will see the resulting repositories appear in the dropdown under your custom list in the Variant Analysis Repositories panel. - -It is possible that some of the resulting repositories do not have CodeQL databases or are not accessible. When you run an analysis on the list, the results view will show you which repositories could not be analyzed. +Not all resulting repositories will have CodeQL databases or allow access to be analyzed. When you run an analysis on the list, the Variant Analysis Results view will show you which repositories could not be analyzed. Troubleshooting variant analysis -------------------------------- From c30f259f9df9c20684068b221ea53541f96f1811 Mon Sep 17 00:00:00 2001 From: Sarita Iyer <66540150+saritai@users.noreply.github.com> Date: Fri, 9 Jun 2023 16:28:34 -0400 Subject: [PATCH 072/364] provide more info --- .../running-codeql-queries-at-scale-with-mrva.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst index f225b3e8097..f4ab2c1e3ee 100644 --- a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst +++ b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst @@ -181,7 +181,7 @@ Custom lists can contain a maximum of 1000 repositories, so at most only the fir You can view the progress of your search in the bottom right corner of the application in a box with the text "Searching for repositories...". If you click **Cancel**, no repositories will be added to your list. Once complete, you will see the resulting repositories appear in the dropdown under your custom list in the Variant Analysis Repositories panel. -Not all resulting repositories will have CodeQL databases or allow access to be analyzed. When you run an analysis on the list, the Variant Analysis Results view will show you which repositories could not be analyzed. +Not all resulting repositories will have CodeQL databases or allow access to be analyzed. When you run an analysis on the list, the Variant Analysis Results view will show you which repositories were analyzed, which denied access, and which had no CodeQL database. Troubleshooting variant analysis -------------------------------- From 68b6d6207e57def18ac771988c3d52a257f63305 Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Mon, 12 Jun 2023 09:35:20 +0100 Subject: [PATCH 073/364] Update docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst --- .../running-codeql-queries-at-scale-with-mrva.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst index f4ab2c1e3ee..e82b0243294 100644 --- a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst +++ b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst @@ -154,7 +154,7 @@ For example, if you want to continue analyzing a set of repositories that had re You can then insert the ``new-repo-list`` of repositories into your list of custom repository lists for easy access in the Variant Analysis Repositories panel. Using GitHub code search to add repositories to a custom list -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can use code search directly in the CodeQL extension to add a subset of repositories from GitHub.com to a custom list. From 082c9a26d81ca9734b5ec72b13423680d9ec5e59 Mon Sep 17 00:00:00 2001 From: Sarita Iyer <66540150+saritai@users.noreply.github.com> Date: Mon, 12 Jun 2023 09:22:42 -0400 Subject: [PATCH 074/364] Update docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst Co-authored-by: Felicity Chapman --- .../running-codeql-queries-at-scale-with-mrva.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst index e82b0243294..9160a941718 100644 --- a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst +++ b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst @@ -181,7 +181,7 @@ Custom lists can contain a maximum of 1000 repositories, so at most only the fir You can view the progress of your search in the bottom right corner of the application in a box with the text "Searching for repositories...". If you click **Cancel**, no repositories will be added to your list. Once complete, you will see the resulting repositories appear in the dropdown under your custom list in the Variant Analysis Repositories panel. -Not all resulting repositories will have CodeQL databases or allow access to be analyzed. When you run an analysis on the list, the Variant Analysis Results view will show you which repositories were analyzed, which denied access, and which had no CodeQL database. +Some of the resulting repositories will not have CodeQL databases and some may not allow access by the CodeQL extension for Visual Studio Code. When you run an analysis on the list, the Variant Analysis Results view will show you which repositories were analyzed, which denied access, and which had no CodeQL database. Troubleshooting variant analysis -------------------------------- From 8c59ec2ec74c6822a6e41dafc62e69b0ca7736aa Mon Sep 17 00:00:00 2001 From: Sarita Iyer <66540150+saritai@users.noreply.github.com> Date: Mon, 12 Jun 2023 09:59:58 -0400 Subject: [PATCH 075/364] revise maximum info --- .../running-codeql-queries-at-scale-with-mrva.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst index f4ab2c1e3ee..d5c9c4197b0 100644 --- a/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst +++ b/docs/codeql/codeql-for-visual-studio-code/running-codeql-queries-at-scale-with-mrva.rst @@ -166,7 +166,7 @@ You can use code search directly in the CodeQL extension to add a subset of repo For example, to add all repositories in the ``rails`` organization on GitHub, you can search ``org:rails``. -Custom lists can contain a maximum of 1000 repositories, so at most only the first 1000 repositories returned from your search will be added to your list. +You can add a maximum of 1000 repositories to a custom list per search. #. In the Variant Analysis Repositories panel, choose the list that you want to add repositories to. You can create a new list or choose an existing list that already contains repositories. From 2fd2c434f2b419e6db77a4d947c056b08f489578 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 13 Jun 2023 09:24:15 +0200 Subject: [PATCH 076/364] Apply suggestions from code review Co-authored-by: Jami <57204504+jcogs33@users.noreply.github.com> --- java/ql/lib/ext/java.lang.model.yml | 3 +-- java/ql/lib/ext/org.apache.commons.exec.model.yml | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml index d3737a62d9f..169440fe591 100644 --- a/java/ql/lib/ext/java.lang.model.yml +++ b/java/ql/lib/ext/java.lang.model.yml @@ -8,8 +8,7 @@ extensions: - ["java.lang", "ClassLoader", True, "getSystemResource", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.lang", "ClassLoader", True, "getSystemResourceAsStream", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] - ["java.lang", "Module", True, "getResourceAsStream", "(String)", "", "Argument[0]", "path-injection", "ai-manual"] - - ["java.lang", "ProcessBuilder", False, "command", "(List)", "", "Argument[0]", "command-injection", "ai-manual"] - - ["java.lang", "ProcessBuilder", False, "command", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] + - ["java.lang", "ProcessBuilder", False, "command", "(List)", "", "Argument[0]", "command-injection", "manual"] - ["java.lang", "ProcessBuilder", False, "command", "(String[])", "", "Argument[0]", "command-injection", "ai-manual"] - ["java.lang", "ProcessBuilder", False, "directory", "(File)", "", "Argument[0]", "command-injection", "ai-manual"] - ["java.lang", "ProcessBuilder", False, "ProcessBuilder", "(List)", "", "Argument[0]", "command-injection", "ai-manual"] diff --git a/java/ql/lib/ext/org.apache.commons.exec.model.yml b/java/ql/lib/ext/org.apache.commons.exec.model.yml index 7b65ee46a49..314b0996194 100644 --- a/java/ql/lib/ext/org.apache.commons.exec.model.yml +++ b/java/ql/lib/ext/org.apache.commons.exec.model.yml @@ -7,3 +7,5 @@ extensions: - ["org.apache.commons.exec", "CommandLine", True, "parse", "(String,Map)", "", "Argument[0]", "command-injection", "manual"] - ["org.apache.commons.exec", "CommandLine", True, "addArguments", "(String)", "", "Argument[0]", "command-injection", "manual"] - ["org.apache.commons.exec", "CommandLine", True, "addArguments", "(String,boolean)", "", "Argument[0]", "command-injection", "manual"] + - ["org.apache.commons.exec", "CommandLine", True, "addArguments", "(String[])", "", "Argument[0]", "command-injection", "manual"] + - ["org.apache.commons.exec", "CommandLine", True, "addArguments", "(String[],boolean)", "", "Argument[0]", "command-injection", "manual"] From 29d4b6fadc170cef201b6c9fc3dbdca5d4f00a0b Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 13 Jun 2023 09:22:37 +0200 Subject: [PATCH 077/364] Re-add public classes that shouldn't be removed yet --- java/ql/lib/semmle/code/java/JDK.qll | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/java/ql/lib/semmle/code/java/JDK.qll b/java/ql/lib/semmle/code/java/JDK.qll index 62115884c62..156cbbc0f93 100644 --- a/java/ql/lib/semmle/code/java/JDK.qll +++ b/java/ql/lib/semmle/code/java/JDK.qll @@ -3,6 +3,7 @@ */ import Member +import semmle.code.java.security.ExternalProcess private import semmle.code.java.dataflow.FlowSteps // --- Standard types --- @@ -197,6 +198,39 @@ class TypeFile extends Class { } // --- Standard methods --- +/** + * DEPRECATED: Any constructor of class `java.lang.ProcessBuilder`. + */ +deprecated class ProcessBuilderConstructor extends Constructor, ExecCallable { + ProcessBuilderConstructor() { this.getDeclaringType() instanceof TypeProcessBuilder } + + override int getAnExecutedArgument() { result = 0 } +} + +/** + * DEPRECATED: Any of the methods named `command` on class `java.lang.ProcessBuilder`. + */ +deprecated class MethodProcessBuilderCommand extends Method, ExecCallable { + MethodProcessBuilderCommand() { + this.hasName("command") and + this.getDeclaringType() instanceof TypeProcessBuilder + } + + override int getAnExecutedArgument() { result = 0 } +} + +/** + * DEPRECATED: Any method named `exec` on class `java.lang.Runtime`. + */ +deprecated class MethodRuntimeExec extends Method, ExecCallable { + MethodRuntimeExec() { + this.hasName("exec") and + this.getDeclaringType() instanceof TypeRuntime + } + + override int getAnExecutedArgument() { result = 0 } +} + /** * Any method named `getenv` on class `java.lang.System`. */ From 8cae151883999562eb07308557f2d848c53e8db5 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 13 Jun 2023 11:22:54 +0200 Subject: [PATCH 078/364] Update python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll Co-authored-by: Asger F --- .../dataflow/typetracking-summaries/TestSummaries.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll b/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll index 1a6a504e1ee..c139308c00e 100644 --- a/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll +++ b/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll @@ -4,7 +4,7 @@ private import semmle.python.ApiGraphs /** * This module ensures that the `callStep` predicate in - * our type tracker implelemtation does not refer to the + * our type tracker implementation does not refer to the * `getACall` predicate on `SummarizedCallable`. */ module RecursionGuard { From 203f8226cb29d183d7b5bb6a2daa65819058ff22 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 13 Jun 2023 11:32:06 +0200 Subject: [PATCH 079/364] ruby/python: make `SummaryTypeTracker` private --- .../python/dataflow/new/internal/TypeTrackerSpecific.qll | 4 ++-- ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index 11e49f5f510..6acc4036c16 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -179,7 +179,7 @@ private predicate argumentPositionMatch( ) } -module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { +private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { // Dataflow nodes class Node = DataFlowPublic::Node; @@ -258,4 +258,4 @@ module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { Node callTo(SummarizedCallable callable) { result = callable.getACallSimple() } } -module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow; +private module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow; diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll index a096f33bd5c..b344fcf127f 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll @@ -350,7 +350,7 @@ predicate isNonLocal(SummaryComponent component) { private import SummaryTypeTracker as SummaryTypeTracker private import codeql.ruby.dataflow.FlowSummary as FlowSummary -module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { +private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { // Dataflow nodes class Node = DataFlow::Node; @@ -448,4 +448,4 @@ module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { Node callTo(SummarizedCallable callable) { result.asExpr().getExpr() = callable.getACallSimple() } } -module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow; +private module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow; From b5961c7f6be954beb91b8ecd6cedb4e7dbfe0a15 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 13 Jun 2023 11:37:19 +0200 Subject: [PATCH 080/364] ruby: move to internal folder --- config/identical-files.json | 4 ++-- ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll | 2 +- .../ruby/typetracking/{ => internal}/SummaryTypeTracker.qll | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename ruby/ql/lib/codeql/ruby/typetracking/{ => internal}/SummaryTypeTracker.qll (100%) diff --git a/config/identical-files.json b/config/identical-files.json index 7a66b2d52f4..39dadd75ab3 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -525,7 +525,7 @@ ], "SummaryTypeTracker": [ "python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll", - "ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll" + "ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll" ], "AccessPathSyntax": [ "csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll", @@ -603,4 +603,4 @@ "python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll", "java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll" ] -} +} \ No newline at end of file diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll index b344fcf127f..484dbdd4197 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll @@ -347,7 +347,7 @@ predicate isNonLocal(SummaryComponent component) { component = SC::withContent(_) } -private import SummaryTypeTracker as SummaryTypeTracker +private import internal.SummaryTypeTracker as SummaryTypeTracker private import codeql.ruby.dataflow.FlowSummary as FlowSummary private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { diff --git a/ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll similarity index 100% rename from ruby/ql/lib/codeql/ruby/typetracking/SummaryTypeTracker.qll rename to ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll From e11f6b5107f80a167e5fbe069114ca0fd211a264 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 13 Jun 2023 11:42:53 +0200 Subject: [PATCH 081/364] ruby/python: adjust shared file - move `isNonLocal` to the top - missing backtics --- .../dataflow/new/internal/SummaryTypeTracker.qll | 16 ++++++++-------- .../typetracking/internal/SummaryTypeTracker.qll | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll index 4e0636826b8..d1a65e1c3e5 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll @@ -133,6 +133,13 @@ signature module Output { * Implementation of the summary type tracker, that is type tracking through flow summaries. */ module SummaryFlow implements Output { + pragma[nomagic] + private predicate isNonLocal(I::SummaryComponent component) { + component = I::content(_) + or + component = I::withContent(_) + } + pragma[nomagic] private predicate hasLoadSummary( I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input, @@ -210,15 +217,8 @@ module SummaryFlow implements Output { ) } - pragma[nomagic] - private predicate isNonLocal(I::SummaryComponent component) { - component = I::content(_) - or - component = I::withContent(_) - } - /** - * Gets a data flow I::Node corresponding an argument or return value of `call`, + * Gets a data flow `I::Node` corresponding an argument or return value of `call`, * as specified by `component`. */ bindingset[call, component] diff --git a/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll index 4e0636826b8..d1a65e1c3e5 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll @@ -133,6 +133,13 @@ signature module Output { * Implementation of the summary type tracker, that is type tracking through flow summaries. */ module SummaryFlow implements Output { + pragma[nomagic] + private predicate isNonLocal(I::SummaryComponent component) { + component = I::content(_) + or + component = I::withContent(_) + } + pragma[nomagic] private predicate hasLoadSummary( I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input, @@ -210,15 +217,8 @@ module SummaryFlow implements Output { ) } - pragma[nomagic] - private predicate isNonLocal(I::SummaryComponent component) { - component = I::content(_) - or - component = I::withContent(_) - } - /** - * Gets a data flow I::Node corresponding an argument or return value of `call`, + * Gets a data flow `I::Node` corresponding an argument or return value of `call`, * as specified by `component`. */ bindingset[call, component] From 33ad15e989f2db19b9ba3c4298b5a536581c0bc7 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 13 Jun 2023 11:48:06 +0200 Subject: [PATCH 082/364] ruby: use aliases --- .../ruby/typetracking/TypeTrackerSpecific.qll | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll index 484dbdd4197..d14c182d127 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll @@ -394,28 +394,18 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { class SummaryComponentStack = FlowSummary::SummaryComponentStack; - SummaryComponentStack singleton(SummaryComponent component) { - result = FlowSummary::SummaryComponentStack::singleton(component) - } + predicate singleton = FlowSummary::SummaryComponentStack::singleton/1; - SummaryComponentStack push(SummaryComponent component, SummaryComponentStack stack) { - result = FlowSummary::SummaryComponentStack::push(component, stack) - } + predicate push = FlowSummary::SummaryComponentStack::push/2; // Relating content to summaries - SummaryComponent content(TypeTrackerContent contents) { - result = FlowSummary::SummaryComponent::content(contents) - } + predicate content = FlowSummary::SummaryComponent::content/1; - SummaryComponent withoutContent(TypeTrackerContent contents) { - result = FlowSummary::SummaryComponent::withoutContent(contents) - } + predicate withoutContent = FlowSummary::SummaryComponent::withoutContent/1; - SummaryComponent withContent(TypeTrackerContent contents) { - result = FlowSummary::SummaryComponent::withContent(contents) - } + predicate withContent = FlowSummary::SummaryComponent::withContent/1; - SummaryComponent return() { result = FlowSummary::SummaryComponent::return() } + predicate return = FlowSummary::SummaryComponent::return/0; // Callables class SummarizedCallable = FlowSummary::SummarizedCallable; From af1ca7fec74d9011a78fce06460af3905da0ce42 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 13 Jun 2023 12:37:31 +0100 Subject: [PATCH 083/364] Update ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll Co-authored-by: Asger F --- ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll index 5ea8ad38f29..bfdd988ac19 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll @@ -14,7 +14,7 @@ private class CallMethodNode extends DataFlow::MethodNode { private DataFlow::LocalSourceNode trackRackResponse(TypeBackTracker t, CallMethodNode call) { t.start() and - result = call.getAReturnNode() + result = call.getAReturnNode().getALocalSource() or exists(TypeBackTracker t2 | result = trackRackResponse(t2, call).backtrack(t2, t)) } From 977ceb89fd8538b75cbf58584d4c24d009ae2f26 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 13 Jun 2023 12:42:46 +0100 Subject: [PATCH 084/364] Ruby: rack - remove PotentialResponseNode#getAStatusCode --- .../frameworks/rack/internal/Response.qll | 20 ++++--------------- .../frameworks/rack/Rack.expected | 8 -------- .../library-tests/frameworks/rack/Rack.ql | 6 ------ 3 files changed, 4 insertions(+), 30 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll index d5ca488fcda..9d998c780ae 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Response.qll @@ -12,25 +12,11 @@ private import App as A /** Contains implementation details for modeling `Rack::Response`. */ module Private { - private DataFlow::LocalSourceNode trackInt(TypeTracker t, int i) { - t.start() and - result.getConstantValue().isInt(i) - or - exists(TypeTracker t2 | result = trackInt(t2, i).track(t2, t)) - } - - private DataFlow::Node trackInt(int i) { trackInt(TypeTracker::end(), i).flowsTo(result) } - /** A `DataFlow::Node` that may be a rack response. This is detected heuristically, if something "looks like" a rack response syntactically then we consider it to be a potential response node. */ class PotentialResponseNode extends DataFlow::ArrayLiteralNode { // [status, headers, body] PotentialResponseNode() { this.getNumberOfArguments() = 3 } - /** - * Gets an HTTP status code that may be returned in this response. - */ - int getAStatusCode() { this.getElement(0) = trackInt(result) } - /** Gets the headers returned with this response. */ DataFlow::Node getHeaders() { result = this.getElement(1) } @@ -87,8 +73,10 @@ module Public { /** A `DataFlow::Node` returned from a rack request that has a redirect HTTP status code. */ class RedirectResponse extends ResponseNode, Http::Server::HttpRedirectResponse::Range { - RedirectResponse() { this.getAStatusCode() = [300, 301, 302, 303, 307, 308] } + private DataFlow::Node redirectLocation; - override DataFlow::Node getRedirectLocation() { result = getHeaderValue(this, "location") } + RedirectResponse() { redirectLocation = getHeaderValue(this, "location") } + + override DataFlow::Node getRedirectLocation() { result = redirectLocation } } } diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.expected b/ruby/ql/test/library-tests/frameworks/rack/Rack.expected index 157168f0bd8..a2671c95cb7 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.expected +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.expected @@ -4,14 +4,6 @@ rackApps | rack.rb:24:1:37:3 | Logger | rack.rb:30:12:30:14 | env | | rack.rb:39:1:45:3 | Redirector | rack.rb:40:12:40:14 | env | | rack.rb:59:1:75:3 | Baz | rack.rb:60:12:60:14 | env | -rackResponseStatusCodes -| rack.rb:8:5:8:38 | call to [] | 200 | -| rack.rb:8:5:8:38 | call to [] | 500 | -| rack.rb:20:5:20:27 | call to [] | | -| rack.rb:35:5:35:26 | call to [] | | -| rack.rb:43:5:43:45 | call to [] | 302 | -| rack.rb:66:7:66:22 | call to [] | 200 | -| rack.rb:73:5:73:21 | call to [] | 400 | rackResponseContentTypes | rack.rb:8:5:8:38 | call to [] | rack.rb:7:34:7:45 | "text/plain" | | rack.rb:20:5:20:27 | call to [] | rack.rb:19:28:19:54 | call to mime_type | diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql index 8e0bcee4244..1b019cdd3a0 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql @@ -6,12 +6,6 @@ query predicate rackApps(Rack::App::AppCandidate c, DataFlow::ParameterNode env) env = c.getEnv() } -query predicate rackResponseStatusCodes(Rack::Response::ResponseNode resp, string status) { - if exists(resp.getAStatusCode()) - then status = resp.getAStatusCode().toString() - else status = "" -} - query predicate rackResponseContentTypes( Rack::Response::ResponseNode resp, DataFlow::Node contentType ) { From 75ccbe58ee27d656b8ae99c39d6a0f48592b489e Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 13 Jun 2023 12:44:29 +0100 Subject: [PATCH 085/364] Ruby: rack - use Mimetype rather than MimeType in predicate names for consistency with concepts --- ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll | 4 ++-- ruby/ql/test/library-tests/frameworks/rack/Rack.ql | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll index f9bd42c15b0..c7682c25638 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll @@ -5,7 +5,7 @@ private import codeql.ruby.ApiGraphs private import codeql.ruby.DataFlow -private predicate mimeTypeMatches(string ext, string mimeType) { +private predicate mimetypeMatches(string ext, string mimeType) { ext = ".123" and mimeType = "application/vnd.lotus-1-2-3" or ext = ".3dml" and mimeType = "text/vnd.in3d.3dml" @@ -1306,6 +1306,6 @@ module Mime { } /** Gets the canonical MIME type string returned by this call. */ - string getMimeType() { mimeTypeMatches(this.getExtension(), result) } + string getMimetype() { mimetypeMatches(this.getExtension(), result) } } } diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql index 1b019cdd3a0..e1f1c506994 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql @@ -13,7 +13,7 @@ query predicate rackResponseContentTypes( } query predicate mimetypeCalls(Rack::Mime::MimetypeCall c, string mimetype) { - mimetype = c.getMimeType() + mimetype = c.getMimetype() } query predicate redirectResponses(Rack::Response::RedirectResponse resp, DataFlow::Node location) { From ae8bf5ed3c0f29b1d26c156b8688bdc16ed2d8fa Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 12 Jun 2023 11:33:17 +0200 Subject: [PATCH 086/364] delete old deprecations --- .../lib/semmle/python/security/Exceptions.qll | 103 ------ .../ql/lib/semmle/python/security/Paths.qll | 16 - .../python/security/injection/Command.qll | 263 --------------- .../semmle/python/security/injection/Sql.qll | 83 ----- .../semmle/python/security/strings/Basic.qll | 124 ------- .../semmle/python/security/strings/Common.qll | 14 - .../python/security/strings/External.qll | 318 ------------------ .../python/security/strings/Untrusted.qll | 10 - .../semmle/python/web/ClientHttpRequest.qll | 2 - python/ql/lib/semmle/python/web/Http.qll | 119 ------- .../lib/semmle/python/web/HttpConstants.qll | 7 - .../ql/lib/semmle/python/web/HttpRedirect.qll | 7 - .../ql/lib/semmle/python/web/HttpRequest.qll | 10 - .../ql/lib/semmle/python/web/HttpResponse.qll | 10 - .../lib/semmle/python/web/bottle/General.qll | 46 --- .../lib/semmle/python/web/bottle/Redirect.qll | 28 -- .../lib/semmle/python/web/bottle/Request.qll | 80 ----- .../lib/semmle/python/web/bottle/Response.qll | 52 --- .../semmle/python/web/cherrypy/General.qll | 44 --- .../semmle/python/web/cherrypy/Request.qll | 41 --- .../semmle/python/web/cherrypy/Response.qll | 18 - .../lib/semmle/python/web/client/Requests.qll | 22 -- .../lib/semmle/python/web/client/StdLib.qll | 55 --- python/ql/lib/semmle/python/web/django/Db.qll | 50 --- .../lib/semmle/python/web/django/General.qll | 136 -------- .../ql/lib/semmle/python/web/django/Model.qll | 69 ---- .../lib/semmle/python/web/django/Redirect.qll | 37 -- .../lib/semmle/python/web/django/Request.qll | 78 ----- .../lib/semmle/python/web/django/Response.qll | 79 ----- .../semmle/python/web/django/Sanitizers.qll | 6 - .../lib/semmle/python/web/django/Shared.qll | 72 ---- .../lib/semmle/python/web/falcon/General.qll | 46 --- .../lib/semmle/python/web/falcon/Request.qll | 37 -- .../lib/semmle/python/web/falcon/Response.qll | 28 -- .../lib/semmle/python/web/flask/General.qll | 104 ------ .../lib/semmle/python/web/flask/Redirect.qll | 26 -- .../lib/semmle/python/web/flask/Request.qll | 80 ----- .../lib/semmle/python/web/flask/Response.qll | 55 --- .../semmle/python/web/pyramid/Redirect.qll | 33 -- .../lib/semmle/python/web/pyramid/Request.qll | 25 -- .../semmle/python/web/pyramid/Response.qll | 37 -- .../ql/lib/semmle/python/web/pyramid/View.qll | 9 - .../lib/semmle/python/web/stdlib/Request.qll | 126 ------- .../lib/semmle/python/web/stdlib/Response.qll | 43 --- .../semmle/python/web/tornado/Redirect.qll | 28 -- .../lib/semmle/python/web/tornado/Request.qll | 69 ---- .../semmle/python/web/tornado/Response.qll | 47 --- .../lib/semmle/python/web/tornado/Tornado.qll | 50 --- .../semmle/python/web/turbogears/Request.qll | 26 -- .../semmle/python/web/turbogears/Response.qll | 31 -- .../python/web/turbogears/TurboGears.qll | 37 -- .../lib/semmle/python/web/twisted/Request.qll | 30 -- .../semmle/python/web/twisted/Response.qll | 45 --- .../lib/semmle/python/web/twisted/Twisted.qll | 52 --- .../lib/semmle/python/web/webob/Request.qll | 38 --- .../experimental/Security/CWE-074/JinjaBad.py | 19 -- .../Security/CWE-074/JinjaGood.py | 20 -- .../Security/CWE-074/TemplateInjection.qhelp | 24 -- .../Security/CWE-074/TemplateInjection.ql | 35 -- .../experimental/Security/CWE-091/Xslt.qhelp | 18 - .../src/experimental/Security/CWE-091/Xslt.ql | 36 -- .../src/experimental/Security/CWE-091/xslt.py | 14 - .../semmle/python/security/injection/XSLT.qll | 42 --- .../semmle/python/templates/Airspeed.qll | 27 -- .../semmle/python/templates/Bottle.qll | 48 --- .../semmle/python/templates/Chameleon.qll | 29 -- .../semmle/python/templates/Cheetah.qll | 39 --- .../semmle/python/templates/Chevron.qll | 36 -- .../python/templates/DjangoTemplate.qll | 35 -- .../semmle/python/templates/FlaskTemplate.qll | 28 -- .../semmle/python/templates/Genshi.qll | 53 --- .../semmle/python/templates/Jinja.qll | 49 --- .../semmle/python/templates/Mako.qll | 27 -- .../semmle/python/templates/SSTISink.qll | 7 - .../semmle/python/templates/Ssti.qll | 13 - .../semmle/python/templates/TRender.qll | 27 -- .../3/library-tests/taint/strings/Taint.qll | 44 --- .../taint/strings/TestTaint.expected | 1 - .../library-tests/taint/strings/TestTaint.ql | 33 -- .../3/library-tests/taint/strings/test.py | 5 - .../3/library-tests/taint/unpacking/Taint.qll | 27 -- .../taint/unpacking/TestTaint.expected | 9 - .../taint/unpacking/TestTaint.ql | 19 -- .../3/library-tests/taint/unpacking/test.py | 31 -- .../CWE-074/TemplateInjection.expected | 60 ---- .../Security/CWE-074/TemplateInjection.qlref | 1 - .../Security/CWE-091/Xslt.expected | 47 --- .../query-tests/Security/CWE-091/Xslt.qlref | 1 - .../query-tests/Security/CWE-091/xslt.py | 14 - .../semmle/python/templates/Airspeed.py | 10 - .../templates/AirspeedSSTISinks.expected | 2 - .../python/templates/AirspeedSSTISinks.ql | 5 - .../semmle/python/templates/Bottle.py | 17 - .../python/templates/BottleSSTISinks.expected | 3 - .../python/templates/BottleSSTISinks.ql | 5 - .../semmle/python/templates/Chameleon.py | 5 - .../templates/ChameleonSSTISinks.expected | 2 - .../python/templates/ChameleonSSTISinks.ql | 5 - .../templates/CheetahSSTISinks.expected | 3 - .../python/templates/CheetahSSTISinks.ql | 5 - .../semmle/python/templates/CheetahSinks.py | 20 -- .../templates/ChevronSSTISinks.expected | 2 - .../python/templates/ChevronSSTISinks.ql | 5 - .../semmle/python/templates/ChevronSinks.py | 22 -- .../python/templates/DjangoSSTISinks.expected | 2 - .../python/templates/DjangoSSTISinks.ql | 5 - .../python/templates/DjangoTemplates.py | 39 --- .../semmle/python/templates/Genshi.py | 10 - .../python/templates/GenshiSSTISinks.expected | 3 - .../python/templates/GenshiSSTISinks.ql | 5 - .../python/templates/Jinja2Templates.py | 17 - .../python/templates/JinjaSSTISinks.expected | 4 - .../semmle/python/templates/JinjaSSTISinks.ql | 5 - .../semmle/python/templates/Mako.py | 5 - .../python/templates/MakoSSTISinks.expected | 2 - .../semmle/python/templates/MakoSSTISinks.ql | 5 - .../semmle/python/templates/TRender.py | 6 - .../templates/TRenderSSTISinks.expected | 2 - .../python/templates/TRenderSSTISinks.ql | 5 - .../semmle/python/templates/options | 1 - .../custom-sanitizer/SanitizedEdges.expected | 23 -- .../custom-sanitizer/SanitizedEdges.ql | 6 - .../examples/custom-sanitizer/Taint.qll | 77 ----- .../custom-sanitizer/TestTaint.expected | 28 -- .../examples/custom-sanitizer/TestTaint.ql | 31 -- .../examples/custom-sanitizer/test.py | 110 ------ .../command-execution/CommandSinks.expected | 18 - .../command-execution/CommandSinks.ql | 6 - .../security/command-execution/fabric-LICENSE | 22 -- .../command-execution/fabric_v1_test.py | 10 - .../command-execution/fabric_v2_test.py | 33 -- .../security/command-execution/invoke_test.py | 32 -- .../security/command-execution/options | 1 - .../security/fabric-v1-execute/Taint.qll | 24 -- .../fabric-v1-execute/TestTaint.expected | 10 - .../security/fabric-v1-execute/TestTaint.ql | 33 -- .../security/fabric-v1-execute/options | 1 - .../security/fabric-v1-execute/test.py | 28 -- .../library-tests/taint/collections/Taint.qll | 27 -- .../taint/collections/TestStep.expected | 63 ---- .../taint/collections/TestStep.ql | 11 - .../taint/collections/TestTaint.expected | 33 -- .../taint/collections/TestTaint.ql | 19 -- .../library-tests/taint/collections/test.py | 71 ---- .../taint/config/RockPaperScissors.ql | 1 - .../test/library-tests/taint/config/Simple.ql | 1 - .../taint/example/ExampleConfig.ql | 1 - .../exception_traceback/TestNode.expected | 27 -- .../taint/exception_traceback/TestNode.ql | 7 - .../exception_traceback/TestSource.expected | 10 - .../taint/exception_traceback/TestSource.ql | 9 - .../exception_traceback/TestStep.expected | 16 - .../taint/exception_traceback/TestStep.ql | 12 - .../taint/exception_traceback/test.py | 34 -- .../taint/flowpath_regression/Config.qll | 45 --- .../taint/flowpath_regression/Path.expected | 1 - .../taint/flowpath_regression/Path.ql | 6 - .../taint/flowpath_regression/test.py | 22 -- .../taint/namedtuple/SanitizedEdges.expected | 7 - .../taint/namedtuple/SanitizedEdges.ql | 6 - .../library-tests/taint/namedtuple/Taint.qll | 45 --- .../taint/namedtuple/TestTaint.expected | 15 - .../taint/namedtuple/TestTaint.ql | 19 -- .../library-tests/taint/namedtuple/test.py | 44 --- .../library-tests/taint/strings/Taint.qll | 44 --- .../taint/strings/TestStep.expected | 162 --------- .../library-tests/taint/strings/TestStep.ql | 11 - .../taint/strings/TestTaint.expected | 63 ---- .../library-tests/taint/strings/TestTaint.ql | 19 -- .../test/library-tests/taint/strings/test.py | 134 -------- .../library-tests/taint/unpacking/Taint.qll | 27 -- .../taint/unpacking/TestStep.expected | 41 --- .../library-tests/taint/unpacking/TestStep.ql | 11 - .../taint/unpacking/TestTaint.expected | 33 -- .../taint/unpacking/TestTaint.ql | 19 -- .../library-tests/taint/unpacking/test.py | 58 ---- 176 files changed, 5913 deletions(-) delete mode 100644 python/ql/lib/semmle/python/security/Exceptions.qll delete mode 100644 python/ql/lib/semmle/python/security/Paths.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/Command.qll delete mode 100644 python/ql/lib/semmle/python/security/injection/Sql.qll delete mode 100644 python/ql/lib/semmle/python/security/strings/Basic.qll delete mode 100644 python/ql/lib/semmle/python/security/strings/Common.qll delete mode 100644 python/ql/lib/semmle/python/security/strings/External.qll delete mode 100644 python/ql/lib/semmle/python/security/strings/Untrusted.qll delete mode 100644 python/ql/lib/semmle/python/web/ClientHttpRequest.qll delete mode 100644 python/ql/lib/semmle/python/web/Http.qll delete mode 100644 python/ql/lib/semmle/python/web/HttpConstants.qll delete mode 100644 python/ql/lib/semmle/python/web/HttpRedirect.qll delete mode 100644 python/ql/lib/semmle/python/web/HttpRequest.qll delete mode 100644 python/ql/lib/semmle/python/web/HttpResponse.qll delete mode 100644 python/ql/lib/semmle/python/web/bottle/General.qll delete mode 100644 python/ql/lib/semmle/python/web/bottle/Redirect.qll delete mode 100644 python/ql/lib/semmle/python/web/bottle/Request.qll delete mode 100644 python/ql/lib/semmle/python/web/bottle/Response.qll delete mode 100644 python/ql/lib/semmle/python/web/cherrypy/General.qll delete mode 100644 python/ql/lib/semmle/python/web/cherrypy/Request.qll delete mode 100644 python/ql/lib/semmle/python/web/cherrypy/Response.qll delete mode 100644 python/ql/lib/semmle/python/web/client/Requests.qll delete mode 100644 python/ql/lib/semmle/python/web/client/StdLib.qll delete mode 100644 python/ql/lib/semmle/python/web/django/Db.qll delete mode 100644 python/ql/lib/semmle/python/web/django/General.qll delete mode 100644 python/ql/lib/semmle/python/web/django/Model.qll delete mode 100644 python/ql/lib/semmle/python/web/django/Redirect.qll delete mode 100644 python/ql/lib/semmle/python/web/django/Request.qll delete mode 100644 python/ql/lib/semmle/python/web/django/Response.qll delete mode 100644 python/ql/lib/semmle/python/web/django/Sanitizers.qll delete mode 100644 python/ql/lib/semmle/python/web/django/Shared.qll delete mode 100644 python/ql/lib/semmle/python/web/falcon/General.qll delete mode 100644 python/ql/lib/semmle/python/web/falcon/Request.qll delete mode 100644 python/ql/lib/semmle/python/web/falcon/Response.qll delete mode 100644 python/ql/lib/semmle/python/web/flask/General.qll delete mode 100644 python/ql/lib/semmle/python/web/flask/Redirect.qll delete mode 100644 python/ql/lib/semmle/python/web/flask/Request.qll delete mode 100644 python/ql/lib/semmle/python/web/flask/Response.qll delete mode 100644 python/ql/lib/semmle/python/web/pyramid/Redirect.qll delete mode 100644 python/ql/lib/semmle/python/web/pyramid/Request.qll delete mode 100644 python/ql/lib/semmle/python/web/pyramid/Response.qll delete mode 100644 python/ql/lib/semmle/python/web/pyramid/View.qll delete mode 100644 python/ql/lib/semmle/python/web/stdlib/Request.qll delete mode 100644 python/ql/lib/semmle/python/web/stdlib/Response.qll delete mode 100644 python/ql/lib/semmle/python/web/tornado/Redirect.qll delete mode 100644 python/ql/lib/semmle/python/web/tornado/Request.qll delete mode 100644 python/ql/lib/semmle/python/web/tornado/Response.qll delete mode 100644 python/ql/lib/semmle/python/web/tornado/Tornado.qll delete mode 100644 python/ql/lib/semmle/python/web/turbogears/Request.qll delete mode 100644 python/ql/lib/semmle/python/web/turbogears/Response.qll delete mode 100644 python/ql/lib/semmle/python/web/turbogears/TurboGears.qll delete mode 100644 python/ql/lib/semmle/python/web/twisted/Request.qll delete mode 100644 python/ql/lib/semmle/python/web/twisted/Response.qll delete mode 100644 python/ql/lib/semmle/python/web/twisted/Twisted.qll delete mode 100644 python/ql/lib/semmle/python/web/webob/Request.qll delete mode 100644 python/ql/src/experimental/Security/CWE-074/JinjaBad.py delete mode 100644 python/ql/src/experimental/Security/CWE-074/JinjaGood.py delete mode 100644 python/ql/src/experimental/Security/CWE-074/TemplateInjection.qhelp delete mode 100644 python/ql/src/experimental/Security/CWE-074/TemplateInjection.ql delete mode 100644 python/ql/src/experimental/Security/CWE-091/Xslt.qhelp delete mode 100644 python/ql/src/experimental/Security/CWE-091/Xslt.ql delete mode 100644 python/ql/src/experimental/Security/CWE-091/xslt.py delete mode 100644 python/ql/src/experimental/semmle/python/templates/Airspeed.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/Bottle.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/Chameleon.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/Cheetah.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/Chevron.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/Genshi.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/Jinja.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/Mako.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/SSTISink.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/Ssti.qll delete mode 100644 python/ql/src/experimental/semmle/python/templates/TRender.qll delete mode 100644 python/ql/test/3/library-tests/taint/strings/Taint.qll delete mode 100644 python/ql/test/3/library-tests/taint/strings/TestTaint.expected delete mode 100644 python/ql/test/3/library-tests/taint/strings/TestTaint.ql delete mode 100644 python/ql/test/3/library-tests/taint/strings/test.py delete mode 100644 python/ql/test/3/library-tests/taint/unpacking/Taint.qll delete mode 100644 python/ql/test/3/library-tests/taint/unpacking/TestTaint.expected delete mode 100644 python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql delete mode 100644 python/ql/test/3/library-tests/taint/unpacking/test.py delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.expected delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.qlref delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.expected delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.qlref delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/xslt.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/Airspeed.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.expected delete mode 100644 python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.ql delete mode 100644 python/ql/test/experimental/semmle/python/templates/Bottle.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.expected delete mode 100644 python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.ql delete mode 100644 python/ql/test/experimental/semmle/python/templates/Chameleon.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.expected delete mode 100644 python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.ql delete mode 100644 python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.expected delete mode 100644 python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.ql delete mode 100644 python/ql/test/experimental/semmle/python/templates/CheetahSinks.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.expected delete mode 100644 python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.ql delete mode 100644 python/ql/test/experimental/semmle/python/templates/ChevronSinks.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.expected delete mode 100644 python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.ql delete mode 100644 python/ql/test/experimental/semmle/python/templates/DjangoTemplates.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/Genshi.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.expected delete mode 100644 python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.ql delete mode 100644 python/ql/test/experimental/semmle/python/templates/Jinja2Templates.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.expected delete mode 100644 python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.ql delete mode 100644 python/ql/test/experimental/semmle/python/templates/Mako.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.expected delete mode 100644 python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.ql delete mode 100644 python/ql/test/experimental/semmle/python/templates/TRender.py delete mode 100644 python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.expected delete mode 100644 python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.ql delete mode 100644 python/ql/test/experimental/semmle/python/templates/options delete mode 100644 python/ql/test/library-tests/examples/custom-sanitizer/SanitizedEdges.expected delete mode 100644 python/ql/test/library-tests/examples/custom-sanitizer/SanitizedEdges.ql delete mode 100644 python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll delete mode 100644 python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.expected delete mode 100644 python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql delete mode 100644 python/ql/test/library-tests/examples/custom-sanitizer/test.py delete mode 100644 python/ql/test/library-tests/security/command-execution/CommandSinks.expected delete mode 100644 python/ql/test/library-tests/security/command-execution/CommandSinks.ql delete mode 100644 python/ql/test/library-tests/security/command-execution/fabric-LICENSE delete mode 100644 python/ql/test/library-tests/security/command-execution/fabric_v1_test.py delete mode 100644 python/ql/test/library-tests/security/command-execution/fabric_v2_test.py delete mode 100644 python/ql/test/library-tests/security/command-execution/invoke_test.py delete mode 100644 python/ql/test/library-tests/security/command-execution/options delete mode 100644 python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll delete mode 100644 python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected delete mode 100644 python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql delete mode 100644 python/ql/test/library-tests/security/fabric-v1-execute/options delete mode 100644 python/ql/test/library-tests/security/fabric-v1-execute/test.py delete mode 100644 python/ql/test/library-tests/taint/collections/Taint.qll delete mode 100644 python/ql/test/library-tests/taint/collections/TestStep.expected delete mode 100644 python/ql/test/library-tests/taint/collections/TestStep.ql delete mode 100644 python/ql/test/library-tests/taint/collections/TestTaint.expected delete mode 100644 python/ql/test/library-tests/taint/collections/TestTaint.ql delete mode 100644 python/ql/test/library-tests/taint/collections/test.py delete mode 100644 python/ql/test/library-tests/taint/exception_traceback/TestNode.expected delete mode 100644 python/ql/test/library-tests/taint/exception_traceback/TestNode.ql delete mode 100644 python/ql/test/library-tests/taint/exception_traceback/TestSource.expected delete mode 100644 python/ql/test/library-tests/taint/exception_traceback/TestSource.ql delete mode 100644 python/ql/test/library-tests/taint/exception_traceback/TestStep.expected delete mode 100644 python/ql/test/library-tests/taint/exception_traceback/TestStep.ql delete mode 100644 python/ql/test/library-tests/taint/exception_traceback/test.py delete mode 100644 python/ql/test/library-tests/taint/flowpath_regression/Config.qll delete mode 100644 python/ql/test/library-tests/taint/flowpath_regression/Path.expected delete mode 100644 python/ql/test/library-tests/taint/flowpath_regression/Path.ql delete mode 100644 python/ql/test/library-tests/taint/flowpath_regression/test.py delete mode 100644 python/ql/test/library-tests/taint/namedtuple/SanitizedEdges.expected delete mode 100644 python/ql/test/library-tests/taint/namedtuple/SanitizedEdges.ql delete mode 100644 python/ql/test/library-tests/taint/namedtuple/Taint.qll delete mode 100644 python/ql/test/library-tests/taint/namedtuple/TestTaint.expected delete mode 100644 python/ql/test/library-tests/taint/namedtuple/TestTaint.ql delete mode 100644 python/ql/test/library-tests/taint/namedtuple/test.py delete mode 100644 python/ql/test/library-tests/taint/strings/Taint.qll delete mode 100644 python/ql/test/library-tests/taint/strings/TestStep.expected delete mode 100644 python/ql/test/library-tests/taint/strings/TestStep.ql delete mode 100644 python/ql/test/library-tests/taint/strings/TestTaint.expected delete mode 100644 python/ql/test/library-tests/taint/strings/TestTaint.ql delete mode 100644 python/ql/test/library-tests/taint/strings/test.py delete mode 100644 python/ql/test/library-tests/taint/unpacking/Taint.qll delete mode 100644 python/ql/test/library-tests/taint/unpacking/TestStep.expected delete mode 100644 python/ql/test/library-tests/taint/unpacking/TestStep.ql delete mode 100644 python/ql/test/library-tests/taint/unpacking/TestTaint.expected delete mode 100644 python/ql/test/library-tests/taint/unpacking/TestTaint.ql delete mode 100644 python/ql/test/library-tests/taint/unpacking/test.py diff --git a/python/ql/lib/semmle/python/security/Exceptions.qll b/python/ql/lib/semmle/python/security/Exceptions.qll deleted file mode 100644 index a335d4e3c35..00000000000 --- a/python/ql/lib/semmle/python/security/Exceptions.qll +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Provides classes and predicates for tracking exceptions and information - * associated with exceptions. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic - -deprecated private Value traceback_function(string name) { - result = Module::named("traceback").attr(name) -} - -/** - * This represents information relating to an exception, for instance the - * message, arguments or parts of the exception traceback. - */ -deprecated class ExceptionInfo extends StringKind { - ExceptionInfo() { this = "exception.info" } - - override string repr() { result = "exception info" } -} - -/** - * A class representing sources of information about - * execution state exposed in tracebacks and the like. - */ -abstract deprecated class ErrorInfoSource extends TaintSource { } - -/** - * This kind represents exceptions themselves. - */ -deprecated class ExceptionKind extends TaintKind { - ExceptionKind() { this = "exception.kind" } - - override string repr() { result = "exception" } - - override TaintKind getTaintOfAttribute(string name) { - name = "args" and result instanceof ExceptionInfoSequence - or - name = "message" and result instanceof ExceptionInfo - } -} - -/** - * A source of exception objects, either explicitly created, or captured by an - * `except` statement. - */ -deprecated class ExceptionSource extends ErrorInfoSource { - ExceptionSource() { - exists(ClassValue cls | - cls.getASuperType() = ClassValue::baseException() and - this.(ControlFlowNode).pointsTo().getClass() = cls - ) - or - this = any(ExceptStmt s).getName().getAFlowNode() - } - - override string toString() { result = "exception.source" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionKind } -} - -/** - * Represents a sequence of pieces of information relating to an exception, - * for instance the contents of the `args` attribute, or the stack trace. - */ -deprecated class ExceptionInfoSequence extends SequenceKind { - ExceptionInfoSequence() { this.getItem() instanceof ExceptionInfo } -} - -/** - * Represents calls to functions in the `traceback` module that return - * sequences of exception information. - */ -deprecated class CallToTracebackFunction extends ErrorInfoSource { - CallToTracebackFunction() { - exists(string name | - name in [ - "extract_tb", "extract_stack", "format_list", "format_exception_only", "format_exception", - "format_tb", "format_stack" - ] - | - this = traceback_function(name).getACall() - ) - } - - override string toString() { result = "exception.info.sequence.source" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfoSequence } -} - -/** - * Represents calls to functions in the `traceback` module that return a single - * string of information about an exception. - */ -deprecated class FormattedTracebackSource extends ErrorInfoSource { - FormattedTracebackSource() { this = traceback_function("format_exc").getACall() } - - override string toString() { result = "exception.info.source" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfo } -} diff --git a/python/ql/lib/semmle/python/security/Paths.qll b/python/ql/lib/semmle/python/security/Paths.qll deleted file mode 100644 index 9288a1eff61..00000000000 --- a/python/ql/lib/semmle/python/security/Paths.qll +++ /dev/null @@ -1,16 +0,0 @@ -import semmle.python.dataflow.Implementation - -deprecated module TaintTrackingPaths { - predicate edge(TaintTrackingNode src, TaintTrackingNode dest, string label) { - exists(TaintTrackingNode source, TaintTrackingNode sink | - source.getConfiguration().hasFlowPath(source, sink) and - source.getASuccessor*() = src and - src.getASuccessor(label) = dest and - dest.getASuccessor*() = sink - ) - } -} - -deprecated query predicate edges(TaintTrackingNode fromnode, TaintTrackingNode tonode) { - TaintTrackingPaths::edge(fromnode, tonode, _) -} diff --git a/python/ql/lib/semmle/python/security/injection/Command.qll b/python/ql/lib/semmle/python/security/injection/Command.qll deleted file mode 100644 index b8ae8b94563..00000000000 --- a/python/ql/lib/semmle/python/security/injection/Command.qll +++ /dev/null @@ -1,263 +0,0 @@ -/** - * Provides class and predicates to track external data that - * may represent malicious OS commands. - * - * This module is intended to be imported into a taint-tracking query - * to extend `TaintKind` and `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted - -/** Abstract taint sink that is potentially vulnerable to malicious shell commands. */ -abstract deprecated class CommandSink extends TaintSink { } - -deprecated private ModuleObject osOrPopenModule() { result.getName() = ["os", "popen2"] } - -deprecated private Object makeOsCall() { - exists(string name | result = ModuleObject::named("subprocess").attr(name) | - name = ["Popen", "call", "check_call", "check_output", "run"] - ) -} - -/**Special case for first element in sequence. */ -deprecated class FirstElementKind extends TaintKind { - FirstElementKind() { this = "sequence[" + any(ExternalStringKind key) + "][0]" } - - override string repr() { result = "first item in sequence of " + this.getItem().repr() } - - /** Gets the taint kind for item in this sequence. */ - ExternalStringKind getItem() { this = "sequence[" + result + "][0]" } -} - -deprecated class FirstElementFlow extends DataFlowExtension::DataFlowNode { - FirstElementFlow() { this = any(SequenceNode s).getElement(0) } - - override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { - result.(SequenceNode).getElement(0) = this and tokind.(FirstElementKind).getItem() = fromkind - } -} - -/** - * A taint sink that is potentially vulnerable to malicious shell commands. - * The `vuln` in `subprocess.call(shell=vuln)` and similar calls. - */ -deprecated class ShellCommand extends CommandSink { - override string toString() { result = "shell command" } - - ShellCommand() { - exists(CallNode call, Object istrue | - call.getFunction().refersTo(makeOsCall()) and - call.getAnArg() = this and - call.getArgByName("shell").refersTo(istrue) and - istrue.booleanValue() = true - ) - or - exists(CallNode call, string name | - call.getAnArg() = this and - call.getFunction().refersTo(osOrPopenModule().attr(name)) - | - name = ["system", "popen"] or - name.matches("popen_") - ) - or - exists(CallNode call | - call.getAnArg() = this and - call.getFunction().refersTo(ModuleObject::named("commands")) - ) - } - - override predicate sinks(TaintKind kind) { - /* Tainted string command */ - kind instanceof ExternalStringKind - or - /* List (or tuple) containing a tainted string command */ - kind instanceof ExternalStringSequenceKind - } -} - -/** - * A taint sink that is potentially vulnerable to malicious shell commands. - * The `vuln` in `subprocess.call(vuln, ...)` and similar calls. - */ -deprecated class OsCommandFirstArgument extends CommandSink { - override string toString() { result = "OS command first argument" } - - OsCommandFirstArgument() { - not this instanceof ShellCommand and - exists(CallNode call | - call.getFunction().refersTo(makeOsCall()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { - /* Tainted string command */ - kind instanceof ExternalStringKind - or - /* List (or tuple) whose first element is tainted */ - kind instanceof FirstElementKind - } -} - -// -------------------------------------------------------------------------- // -// Modeling of the 'invoke' package and 'fabric' package (v 2.x) -// -// Since fabric build so closely upon invoke, we model them together to avoid -// duplication -// -------------------------------------------------------------------------- // -/** - * A taint sink that is potentially vulnerable to malicious shell commands. - * The `vuln` in `invoke.run(vuln, ...)` and similar calls. - */ -deprecated class InvokeRun extends CommandSink { - InvokeRun() { - this = Value::named("invoke.run").(FunctionValue).getArgumentForCall(_, 0) - or - this = Value::named("invoke.sudo").(FunctionValue).getArgumentForCall(_, 0) - } - - override string toString() { result = "InvokeRun" } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -/** - * Internal TaintKind to track the invoke.Context instance passed to functions - * marked with @invoke.task - */ -deprecated private class InvokeContextArg extends TaintKind { - InvokeContextArg() { this = "InvokeContextArg" } -} - -/** Internal TaintSource to track the context passed to functions marked with @invoke.task */ -deprecated private class InvokeContextArgSource extends TaintSource { - InvokeContextArgSource() { - exists(Function f, Expr decorator | - count(f.getADecorator()) = 1 and - ( - decorator = f.getADecorator() and not decorator instanceof Call - or - decorator = f.getADecorator().(Call).getFunc() - ) and - ( - decorator.pointsTo(Value::named("invoke.task")) - or - decorator.pointsTo(Value::named("fabric.task")) - ) - | - this.(ControlFlowNode).getNode() = f.getArg(0) - ) - } - - override predicate isSourceOf(TaintKind kind) { kind instanceof InvokeContextArg } -} - -/** - * A taint sink that is potentially vulnerable to malicious shell commands. - * The `vuln` in `invoke.Context().run(vuln, ...)` and similar calls. - */ -deprecated class InvokeContextRun extends CommandSink { - InvokeContextRun() { - exists(CallNode call | - any(InvokeContextArg k).taints(call.getFunction().(AttrNode).getObject("run")) - or - call = Value::named("invoke.Context").(ClassValue).lookup("run").getACall() - or - // fabric.connection.Connection is a subtype of invoke.context.Context - // since fabric.Connection.run has a decorator, it doesn't work with FunctionValue :| - // and `Value::named("fabric.Connection").(ClassValue).lookup("run").getACall()` returned no results, - // so here is the hacky solution that works :\ - call.getFunction().(AttrNode).getObject("run").pointsTo().getClass() = - Value::named("fabric.Connection") - | - this = call.getArg(0) - or - this = call.getArgByName("command") - ) - } - - override string toString() { result = "InvokeContextRun" } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -/** - * A taint sink that is potentially vulnerable to malicious shell commands. - * The `vuln` in `fabric.Group().run(vuln, ...)` and similar calls. - */ -deprecated class FabricGroupRun extends CommandSink { - FabricGroupRun() { - exists(ClassValue cls | - cls.getASuperType() = Value::named("fabric.Group") and - this = cls.lookup("run").(FunctionValue).getArgumentForCall(_, 1) - ) - } - - override string toString() { result = "FabricGroupRun" } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -// -------------------------------------------------------------------------- // -// Modeling of the 'invoke' package and 'fabric' package (v 1.x) -// -------------------------------------------------------------------------- // -deprecated class FabricV1Commands extends CommandSink { - FabricV1Commands() { - // since `run` and `sudo` are decorated, we can't use FunctionValue's :( - exists(CallNode call | - call = Value::named("fabric.api.local").getACall() - or - call = Value::named("fabric.api.run").getACall() - or - call = Value::named("fabric.api.sudo").getACall() - | - this = call.getArg(0) - or - this = call.getArgByName("command") - ) - } - - override string toString() { result = "FabricV1Commands" } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -/** - * An extension that propagates taint from the arguments of `fabric.api.execute(func, arg0, arg1, ...)` - * to the parameters of `func`, since this will call `func(arg0, arg1, ...)`. - */ -deprecated class FabricExecuteExtension extends DataFlowExtension::DataFlowNode { - CallNode call; - - FabricExecuteExtension() { - call = Value::named("fabric.api.execute").getACall() and - ( - this = call.getArg(any(int i | i > 0)) - or - this = call.getArgByName(any(string s | not s = "task")) - ) - } - - override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { - tokind = fromkind and - exists(CallableValue func | - ( - call.getArg(0).pointsTo(func) - or - call.getArgByName("task").pointsTo(func) - ) and - exists(int i | - // execute(func, arg0, arg1) => func(arg0, arg1) - this = call.getArg(i) and - result = func.getParameter(i - 1) - ) - or - exists(string name | - this = call.getArgByName(name) and - result = func.getParameterByName(name) - ) - ) - } -} diff --git a/python/ql/lib/semmle/python/security/injection/Sql.qll b/python/ql/lib/semmle/python/security/injection/Sql.qll deleted file mode 100644 index b2e2cd47715..00000000000 --- a/python/ql/lib/semmle/python/security/injection/Sql.qll +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Provides class and predicates to track external data that - * may represent malicious SQL queries or parts of queries. - * - * This module is intended to be imported into a taint-tracking query - * to extend `TaintKind` and `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted -import semmle.python.security.SQL - -deprecated private StringObject first_part(ControlFlowNode command) { - command.(BinaryExprNode).getOp() instanceof Add and - command.(BinaryExprNode).getLeft().refersTo(result) - or - exists(CallNode call, SequenceObject seq | call = command | - call = theStrType().lookupAttribute("join") and - call.getArg(0).refersTo(seq) and - seq.getInferredElement(0) = result - ) - or - command.(BinaryExprNode).getOp() instanceof Mod and - command.getNode().(StrConst).getLiteralObject() = result -} - -/** Holds if `command` appears to be a SQL command string of which `inject` is a part. */ -deprecated predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject) { - exists(string prefix | - inject = command.getAChild*() and - first_part(command).getText().regexpMatch(" *" + prefix + ".*") - | - prefix = "CREATE" or prefix = "SELECT" - ) -} - -/** - * A taint kind representing a DB cursor. - * This will be overridden to provide specific kinds of DB cursor. - */ -abstract deprecated class DbCursor extends TaintKind { - bindingset[this] - DbCursor() { any() } - - string getExecuteMethodName() { result = "execute" } -} - -/** - * A part of a string that appears to be a SQL command and is thus - * vulnerable to malicious input. - */ -deprecated class SimpleSqlStringInjection extends SqlInjectionSink { - override string toString() { result = "simple SQL string injection" } - - SimpleSqlStringInjection() { probable_sql_command(_, this) } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -/** - * A taint source representing sources of DB connections. - * This will be overridden to provide specific kinds of DB connection sources. - */ -abstract deprecated class DbConnectionSource extends TaintSource { } - -/** - * A taint sink that is vulnerable to malicious SQL queries. - * The `vuln` in `db.connection.execute(vuln)` and similar. - */ -deprecated class DbConnectionExecuteArgument extends SqlInjectionSink { - override string toString() { result = "db.connection.execute" } - - DbConnectionExecuteArgument() { - exists(CallNode call, DbCursor cursor, string name | - cursor.taints(call.getFunction().(AttrNode).getObject(name)) and - cursor.getExecuteMethodName() = name and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/lib/semmle/python/security/strings/Basic.qll b/python/ql/lib/semmle/python/security/strings/Basic.qll deleted file mode 100644 index 6bbae862c32..00000000000 --- a/python/ql/lib/semmle/python/security/strings/Basic.qll +++ /dev/null @@ -1,124 +0,0 @@ -import python -private import Common -import semmle.python.dataflow.TaintTracking - -/** An extensible kind of taint representing any kind of string. */ -abstract deprecated class StringKind extends TaintKind { - bindingset[this] - StringKind() { this = this } - - override TaintKind getTaintOfMethodResult(string name) { - name in [ - "capitalize", "casefold", "center", "expandtabs", "format", "format_map", "ljust", "lstrip", - "lower", "replace", "rjust", "rstrip", "strip", "swapcase", "title", "upper", "zfill", - /* encode/decode is technically not correct, but close enough */ - "encode", "decode" - ] and - result = this - or - name in ["partition", "rpartition", "rsplit", "split", "splitlines"] and - result.(SequenceKind).getItem() = this - } - - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - result = this and - ( - slice(fromnode, tonode) or - tonode.(BinaryExprNode).getAnOperand() = fromnode or - os_path_join(fromnode, tonode) or - str_format(fromnode, tonode) or - encode_decode(fromnode, tonode) or - to_str(fromnode, tonode) or - f_string(fromnode, tonode) - ) - or - result = this and copy_call(fromnode, tonode) - } - - override ClassValue getType() { - result = Value::named("bytes") or - result = Value::named("str") or - result = Value::named("unicode") - } -} - -deprecated private class StringEqualitySanitizer extends Sanitizer { - StringEqualitySanitizer() { this = "string equality sanitizer" } - - /* The test `if untrusted == "KNOWN_VALUE":` sanitizes `untrusted` on its `true` edge. */ - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - taint instanceof StringKind and - exists(ControlFlowNode const, Cmpop op | const.getNode() instanceof StrConst | - ( - test.getTest().(CompareNode).operands(const, op, _) - or - test.getTest().(CompareNode).operands(_, op, const) - ) and - ( - op instanceof Eq and test.getSense() = true - or - op instanceof NotEq and test.getSense() = false - ) - ) - } -} - -/** tonode = ....format(fromnode) */ -deprecated private predicate str_format(ControlFlowNode fromnode, CallNode tonode) { - tonode.getFunction().(AttrNode).getName() = "format" and - tonode.getAnArg() = fromnode -} - -/** tonode = codec.[en|de]code(fromnode) */ -deprecated private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) { - exists(FunctionObject func, string name | - not func.getFunction().isMethod() and - func.getACall() = tonode and - tonode.getAnArg() = fromnode and - func.getName() = name - | - name = "encode" or - name = "decode" or - name = "decodestring" - ) -} - -/** tonode = str(fromnode) */ -deprecated private predicate to_str(ControlFlowNode fromnode, CallNode tonode) { - tonode.getAnArg() = fromnode and - ( - tonode = ClassValue::bytes().getACall() - or - tonode = ClassValue::unicode().getACall() - ) -} - -/** tonode = fromnode[:] */ -deprecated private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) { - exists(Slice all | - all = tonode.getIndex().getNode() and - not exists(all.getStart()) and - not exists(all.getStop()) and - tonode.getObject() = fromnode - ) -} - -/** tonode = os.path.join(..., fromnode, ...) */ -deprecated private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) { - tonode = Value::named("os.path.join").getACall() and - tonode.getAnArg() = fromnode -} - -/** tonode = f"... {fromnode} ..." */ -deprecated private predicate f_string(ControlFlowNode fromnode, ControlFlowNode tonode) { - tonode.getNode().(Fstring).getAValue() = fromnode.getNode() -} - -/** - * A kind of "taint", representing a dictionary mapping str->"taint" - * - * DEPRECATED: Use `ExternalStringDictKind` instead. - */ -deprecated class StringDictKind extends DictKind { - StringDictKind() { this.getValue() instanceof StringKind } -} diff --git a/python/ql/lib/semmle/python/security/strings/Common.qll b/python/ql/lib/semmle/python/security/strings/Common.qll deleted file mode 100644 index cb19fdd5461..00000000000 --- a/python/ql/lib/semmle/python/security/strings/Common.qll +++ /dev/null @@ -1,14 +0,0 @@ -import python - -/** A call that returns a copy (or similar) of the argument */ -deprecated predicate copy_call(ControlFlowNode fromnode, CallNode tonode) { - tonode.getFunction().(AttrNode).getObject("copy") = fromnode - or - exists(ModuleValue copy, string name | name = "copy" or name = "deepcopy" | - copy.attr(name).(FunctionValue).getACall() = tonode and - tonode.getArg(0) = fromnode - ) - or - tonode.getFunction().pointsTo(Value::named("reversed")) and - tonode.getArg(0) = fromnode -} diff --git a/python/ql/lib/semmle/python/security/strings/External.qll b/python/ql/lib/semmle/python/security/strings/External.qll deleted file mode 100644 index a5116e42e4e..00000000000 --- a/python/ql/lib/semmle/python/security/strings/External.qll +++ /dev/null @@ -1,318 +0,0 @@ -import python -import Basic -private import Common - -/** - * An extensible kind of taint representing an externally controlled string. - */ -abstract deprecated class ExternalStringKind extends StringKind { - bindingset[this] - ExternalStringKind() { this = this } - - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - result = StringKind.super.getTaintForFlowStep(fromnode, tonode) - or - tonode.(SequenceNode).getElement(_) = fromnode and - result.(ExternalStringSequenceKind).getItem() = this - or - json_load(fromnode, tonode) and result.(ExternalJsonKind).getValue() = this - or - tonode.(DictNode).getAValue() = fromnode and result.(ExternalStringDictKind).getValue() = this - or - urlsplit(fromnode, tonode) and result.(ExternalUrlSplitResult).getItem() = this - or - urlparse(fromnode, tonode) and result.(ExternalUrlParseResult).getItem() = this - or - parse_qs(fromnode, tonode) and result.(ExternalStringDictKind).getValue() = this - or - parse_qsl(fromnode, tonode) and result.(SequenceKind).getItem().(SequenceKind).getItem() = this - } -} - -/** A kind of "taint", representing a sequence, with a "taint" member */ -deprecated class ExternalStringSequenceKind extends SequenceKind { - ExternalStringSequenceKind() { this.getItem() instanceof ExternalStringKind } -} - -/** - * An hierarchical dictionary or list where the entire structure is externally controlled - * This is typically a parsed JSON object. - */ -deprecated class ExternalJsonKind extends TaintKind { - ExternalJsonKind() { this = "json[" + any(ExternalStringKind key) + "]" } - - /** Gets the taint kind for item in this sequence */ - TaintKind getValue() { - this = "json[" + result + "]" - or - result = this - } - - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - this.taints(fromnode) and - json_subscript_taint(tonode, fromnode, this, result) - or - result = this and copy_call(fromnode, tonode) - } - - override TaintKind getTaintOfMethodResult(string name) { - name = "get" and result = this.getValue() - } -} - -/** A kind of "taint", representing a dictionary mapping keys to tainted strings. */ -deprecated class ExternalStringDictKind extends DictKind { - ExternalStringDictKind() { this.getValue() instanceof ExternalStringKind } -} - -/** - * A kind of "taint", representing a dictionary mapping keys to sequences of - * tainted strings. - */ -deprecated class ExternalStringSequenceDictKind extends DictKind { - ExternalStringSequenceDictKind() { this.getValue() instanceof ExternalStringSequenceKind } -} - -/** TaintKind for the result of `urlsplit(tainted_string)` */ -deprecated class ExternalUrlSplitResult extends ExternalStringSequenceKind { - // https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlsplit - override TaintKind getTaintOfAttribute(string name) { - result = super.getTaintOfAttribute(name) - or - name in [ - // namedtuple field names - "scheme", "netloc", "path", "query", "fragment", - // class methods - "password", "username", "hostname", - ] and - result instanceof ExternalStringKind - } - - override TaintKind getTaintOfMethodResult(string name) { - result = super.getTaintOfMethodResult(name) - or - name = "geturl" and - result instanceof ExternalStringKind - } -} - -/** TaintKind for the result of `urlparse(tainted_string)` */ -deprecated class ExternalUrlParseResult extends ExternalStringSequenceKind { - // https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlparse - override TaintKind getTaintOfAttribute(string name) { - result = super.getTaintOfAttribute(name) - or - name in [ - // namedtuple field names - "scheme", "netloc", "path", "params", "query", "fragment", - // class methods - "username", "password", "hostname", - ] and - result instanceof ExternalStringKind - } - - override TaintKind getTaintOfMethodResult(string name) { - result = super.getTaintOfMethodResult(name) - or - name = "geturl" and - result instanceof ExternalStringKind - } -} - -/* Helper for getTaintForStep() */ -pragma[noinline] -deprecated private predicate json_subscript_taint( - SubscriptNode sub, ControlFlowNode obj, ExternalJsonKind seq, TaintKind key -) { - sub.isLoad() and - sub.getObject() = obj and - key = seq.getValue() -} - -deprecated private predicate json_load(ControlFlowNode fromnode, CallNode tonode) { - tonode = Value::named("json.loads").getACall() and - tonode.getArg(0) = fromnode -} - -deprecated private predicate urlsplit(ControlFlowNode fromnode, CallNode tonode) { - // This could be implemented as `exists(FunctionValue` without the explicit six part, - // but then our tests will need to import +100 modules, so for now this slightly - // altered version gets to live on. - exists(Value urlsplit | - ( - urlsplit = Value::named("six.moves.urllib.parse.urlsplit") - or - // Python 2 - urlsplit = Value::named("urlparse.urlsplit") - or - // Python 3 - urlsplit = Value::named("urllib.parse.urlsplit") - ) and - tonode = urlsplit.getACall() and - tonode.getArg(0) = fromnode - ) -} - -deprecated private predicate urlparse(ControlFlowNode fromnode, CallNode tonode) { - // This could be implemented as `exists(FunctionValue` without the explicit six part, - // but then our tests will need to import +100 modules, so for now this slightly - // altered version gets to live on. - exists(Value urlparse | - ( - urlparse = Value::named("six.moves.urllib.parse.urlparse") - or - // Python 2 - urlparse = Value::named("urlparse.urlparse") - or - // Python 3 - urlparse = Value::named("urllib.parse.urlparse") - ) and - tonode = urlparse.getACall() and - tonode.getArg(0) = fromnode - ) -} - -deprecated private predicate parse_qs(ControlFlowNode fromnode, CallNode tonode) { - // This could be implemented as `exists(FunctionValue` without the explicit six part, - // but then our tests will need to import +100 modules, so for now this slightly - // altered version gets to live on. - exists(Value parse_qs | - ( - parse_qs = Value::named("six.moves.urllib.parse.parse_qs") - or - // Python 2 - parse_qs = Value::named("urlparse.parse_qs") - or - // Python 2 deprecated version of `urlparse.parse_qs` - parse_qs = Value::named("cgi.parse_qs") - or - // Python 3 - parse_qs = Value::named("urllib.parse.parse_qs") - ) and - tonode = parse_qs.getACall() and - ( - tonode.getArg(0) = fromnode - or - tonode.getArgByName("qs") = fromnode - ) - ) -} - -deprecated private predicate parse_qsl(ControlFlowNode fromnode, CallNode tonode) { - // This could be implemented as `exists(FunctionValue` without the explicit six part, - // but then our tests will need to import +100 modules, so for now this slightly - // altered version gets to live on. - exists(Value parse_qsl | - ( - parse_qsl = Value::named("six.moves.urllib.parse.parse_qsl") - or - // Python 2 - parse_qsl = Value::named("urlparse.parse_qsl") - or - // Python 2 deprecated version of `urlparse.parse_qsl` - parse_qsl = Value::named("cgi.parse_qsl") - or - // Python 3 - parse_qsl = Value::named("urllib.parse.parse_qsl") - ) and - tonode = parse_qsl.getACall() and - ( - tonode.getArg(0) = fromnode - or - tonode.getArgByName("qs") = fromnode - ) - ) -} - -/** A kind of "taint", representing an open file-like object from an external source. */ -deprecated class ExternalFileObject extends TaintKind { - ExternalStringKind valueKind; - - ExternalFileObject() { this = "file[" + valueKind + "]" } - - /** Gets the taint kind for the contents of this file */ - TaintKind getValue() { result = valueKind } - - override TaintKind getTaintOfMethodResult(string name) { - name in ["read", "readline"] and result = this.getValue() - or - name = "readlines" and result.(SequenceKind).getItem() = this.getValue() - } - - override TaintKind getTaintForIteration() { result = this.getValue() } -} - -/** - * Temporary sanitizer for the tainted result from `urlsplit` and `urlparse`. Can be used to reduce FPs until - * we have better support for namedtuples. - * - * Will clear **all** taint on a test of the kind. That is, on the true edge of any matching test, - * all fields/indexes will be cleared of taint. - * - * Handles: - * - `if splitres.netloc == "KNOWN_VALUE"` - * - `if splitres[0] == "KNOWN_VALUE"` - */ -deprecated class UrlsplitUrlparseTempSanitizer extends Sanitizer { - // TODO: remove this once we have better support for named tuples - UrlsplitUrlparseTempSanitizer() { this = "UrlsplitUrlparseTempSanitizer" } - - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - ( - taint instanceof ExternalUrlSplitResult - or - taint instanceof ExternalUrlParseResult - ) and - exists(ControlFlowNode full_use | - full_use.(SubscriptNode).getObject() = test.getInput().getAUse() - or - full_use.(AttrNode).getObject() = test.getInput().getAUse() - | - this.clears_taint(full_use, test.getTest(), test.getSense()) - ) - } - - private predicate clears_taint(ControlFlowNode tainted, ControlFlowNode test, boolean sense) { - this.test_equality_with_const(test, tainted, sense) - or - this.test_in_const_seq(test, tainted, sense) - or - test.(UnaryExprNode).getNode().getOp() instanceof Not and - exists(ControlFlowNode nested_test | - nested_test = test.(UnaryExprNode).getOperand() and - this.clears_taint(tainted, nested_test, sense.booleanNot()) - ) - } - - /** holds for `== "KNOWN_VALUE"` on `true` edge, and `!= "KNOWN_VALUE"` on `false` edge */ - private predicate test_equality_with_const(CompareNode cmp, ControlFlowNode tainted, boolean sense) { - exists(ControlFlowNode const, Cmpop op | const.getNode() instanceof StrConst | - ( - cmp.operands(const, op, tainted) - or - cmp.operands(tainted, op, const) - ) and - ( - op instanceof Eq and sense = true - or - op instanceof NotEq and sense = false - ) - ) - } - - /** holds for `in ["KNOWN_VALUE", ...]` on `true` edge, and `not in ["KNOWN_VALUE", ...]` on `false` edge */ - private predicate test_in_const_seq(CompareNode cmp, ControlFlowNode tainted, boolean sense) { - exists(SequenceNode const_seq, Cmpop op | - forall(ControlFlowNode elem | elem = const_seq.getAnElement() | - elem.getNode() instanceof StrConst - ) - | - cmp.operands(tainted, op, const_seq) and - ( - op instanceof In and sense = true - or - op instanceof NotIn and sense = false - ) - ) - } -} diff --git a/python/ql/lib/semmle/python/security/strings/Untrusted.qll b/python/ql/lib/semmle/python/security/strings/Untrusted.qll deleted file mode 100644 index 2916b723a8f..00000000000 --- a/python/ql/lib/semmle/python/security/strings/Untrusted.qll +++ /dev/null @@ -1,10 +0,0 @@ -import python -import External - -/** - * A kind of taint representing an externally controlled string. - * This class is a simple sub-class of `ExternalStringKind`. - */ -deprecated class UntrustedStringKind extends ExternalStringKind { - UntrustedStringKind() { this = "externally controlled string" } -} diff --git a/python/ql/lib/semmle/python/web/ClientHttpRequest.qll b/python/ql/lib/semmle/python/web/ClientHttpRequest.qll deleted file mode 100644 index edcd236e031..00000000000 --- a/python/ql/lib/semmle/python/web/ClientHttpRequest.qll +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.python.web.client.StdLib -import semmle.python.web.client.Requests diff --git a/python/ql/lib/semmle/python/web/Http.qll b/python/ql/lib/semmle/python/web/Http.qll deleted file mode 100644 index 85100e6524e..00000000000 --- a/python/ql/lib/semmle/python/web/Http.qll +++ /dev/null @@ -1,119 +0,0 @@ -import python -import semmle.python.dataflow.Implementation -import semmle.python.security.strings.External -import HttpConstants - -/** Generic taint source from a http request */ -abstract deprecated class HttpRequestTaintSource extends TaintSource { } - -/** - * Taint kind representing the WSGI environment. - * As specified in PEP 3333. https://www.python.org/dev/peps/pep-3333/#environ-variables - */ -deprecated class WsgiEnvironment extends TaintKind { - WsgiEnvironment() { this = "wsgi.environment" } - - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - result = this and Implementation::copyCall(fromnode, tonode) - or - result = this and - tonode.(CallNode).getFunction().pointsTo(ClassValue::dict()) and - tonode.(CallNode).getArg(0) = fromnode - or - exists(Value key, string text | - tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode and - tonode.(CallNode).getArg(0).pointsTo(key) - or - tonode.(SubscriptNode).getObject() = fromnode and - tonode.isLoad() and - tonode.(SubscriptNode).getIndex().pointsTo(key) - | - key = Value::forString(text) and - result instanceof ExternalStringKind and - ( - text = "QUERY_STRING" or - text = "PATH_INFO" or - text.matches("HTTP\\_%") - ) - ) - } -} - -/** - * A standard morsel object from a HTTP request, a value in a cookie, - * typically an instance of `http.cookies.Morsel` - */ -deprecated class UntrustedMorsel extends TaintKind { - UntrustedMorsel() { this = "http.Morsel" } - - override TaintKind getTaintOfAttribute(string name) { - result instanceof ExternalStringKind and - name = "value" - } -} - -/** A standard cookie object from a HTTP request, typically an instance of `http.cookies.SimpleCookie` */ -deprecated class UntrustedCookie extends TaintKind { - UntrustedCookie() { this = "http.Cookie" } - - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - tonode.(SubscriptNode).getObject() = fromnode and - result instanceof UntrustedMorsel - } -} - -abstract deprecated class CookieOperation extends @py_flow_node { - /** Gets a textual representation of this element. */ - abstract string toString(); - - abstract ControlFlowNode getKey(); - - abstract ControlFlowNode getValue(); -} - -abstract deprecated class CookieGet extends CookieOperation { } - -abstract deprecated class CookieSet extends CookieOperation { } - -/** Generic taint sink in a http response */ -abstract deprecated class HttpResponseTaintSink extends TaintSink { - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -abstract deprecated class HttpRedirectTaintSink extends TaintSink { - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -deprecated module Client { - // TODO: user-input in other than URL: - // - `data`, `json` for `requests.post` - // - `body` for `HTTPConnection.request` - // - headers? - // TODO: Add more library support - // - urllib3 https://github.com/urllib3/urllib3 - // - httpx https://github.com/encode/httpx - /** - * An outgoing http request - * - * For example: - * conn = HTTPConnection('example.com') - * conn.request('GET', '/path') - */ - abstract class HttpRequest extends ControlFlowNode { - /** - * Get any ControlFlowNode that is used to construct the final URL. - * - * In the HTTPConnection example, there is a result for both `'example.com'` and for `'/path'`. - */ - abstract ControlFlowNode getAUrlPart(); - - abstract string getMethodUpper(); - } - - /** Taint sink for the URL-part of an outgoing http request */ - class HttpRequestUrlTaintSink extends TaintSink { - HttpRequestUrlTaintSink() { this = any(HttpRequest r).getAUrlPart() } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - } -} diff --git a/python/ql/lib/semmle/python/web/HttpConstants.qll b/python/ql/lib/semmle/python/web/HttpConstants.qll deleted file mode 100644 index e5cebb57729..00000000000 --- a/python/ql/lib/semmle/python/web/HttpConstants.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** Gets an HTTP verb, in upper case */ -deprecated string httpVerb() { - result in ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"] -} - -/** Gets an HTTP verb, in lower case */ -deprecated string httpVerbLower() { result = httpVerb().toLowerCase() } diff --git a/python/ql/lib/semmle/python/web/HttpRedirect.qll b/python/ql/lib/semmle/python/web/HttpRedirect.qll deleted file mode 100644 index cfbe35f30f1..00000000000 --- a/python/ql/lib/semmle/python/web/HttpRedirect.qll +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.security.strings.Basic -import semmle.python.web.django.Redirect -import semmle.python.web.flask.Redirect -import semmle.python.web.tornado.Redirect -import semmle.python.web.pyramid.Redirect -import semmle.python.web.bottle.Redirect diff --git a/python/ql/lib/semmle/python/web/HttpRequest.qll b/python/ql/lib/semmle/python/web/HttpRequest.qll deleted file mode 100644 index 88dd36049b4..00000000000 --- a/python/ql/lib/semmle/python/web/HttpRequest.qll +++ /dev/null @@ -1,10 +0,0 @@ -import semmle.python.web.django.Request -import semmle.python.web.flask.Request -import semmle.python.web.tornado.Request -import semmle.python.web.pyramid.Request -import semmle.python.web.twisted.Request -import semmle.python.web.bottle.Request -import semmle.python.web.turbogears.Request -import semmle.python.web.falcon.Request -import semmle.python.web.cherrypy.Request -import semmle.python.web.stdlib.Request diff --git a/python/ql/lib/semmle/python/web/HttpResponse.qll b/python/ql/lib/semmle/python/web/HttpResponse.qll deleted file mode 100644 index 25a4221ce68..00000000000 --- a/python/ql/lib/semmle/python/web/HttpResponse.qll +++ /dev/null @@ -1,10 +0,0 @@ -import semmle.python.web.django.Response -import semmle.python.web.flask.Response -import semmle.python.web.pyramid.Response -import semmle.python.web.tornado.Response -import semmle.python.web.twisted.Response -import semmle.python.web.bottle.Response -import semmle.python.web.turbogears.Response -import semmle.python.web.falcon.Response -import semmle.python.web.cherrypy.Response -import semmle.python.web.stdlib.Response diff --git a/python/ql/lib/semmle/python/web/bottle/General.qll b/python/ql/lib/semmle/python/web/bottle/General.qll deleted file mode 100644 index cbb42c97305..00000000000 --- a/python/ql/lib/semmle/python/web/bottle/General.qll +++ /dev/null @@ -1,46 +0,0 @@ -import python -import semmle.python.web.Http -import semmle.python.types.Extensions - -/** Gets the bottle module */ -deprecated ModuleValue theBottleModule() { result = Module::named("bottle") } - -/** Gets the bottle.Bottle class */ -deprecated ClassValue theBottleClass() { result = theBottleModule().attr("Bottle") } - -/** - * Holds if `route` is routed to `func` - * by decorating `func` with `app.route(route)` or `route(route)` - */ -deprecated predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func) { - exists(CallNode decorator_call, string name | - route_call.getFunction().(AttrNode).getObject(name).pointsTo().getClass() = theBottleClass() or - route_call.getFunction().pointsTo(theBottleModule().attr(name)) - | - (name = "route" or name = httpVerbLower()) and - decorator_call.getFunction() = route_call and - route_call.getArg(0) = route and - decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func - ) -} - -deprecated class BottleRoute extends ControlFlowNode { - BottleRoute() { bottle_route(this, _, _) } - - string getUrl() { - exists(StrConst url | - bottle_route(this, url.getAFlowNode(), _) and - result = url.getText() - ) - } - - Function getFunction() { bottle_route(this, _, result) } - - Parameter getANamedArgument() { - exists(string name, Function func | - func = this.getFunction() and - func.getArgByName(name) = result and - this.getUrl().matches("%<" + name + ">%") - ) - } -} diff --git a/python/ql/lib/semmle/python/web/bottle/Redirect.qll b/python/ql/lib/semmle/python/web/bottle/Redirect.qll deleted file mode 100644 index 6525cc058eb..00000000000 --- a/python/ql/lib/semmle/python/web/bottle/Redirect.qll +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Provides class representing the `bottle.redirect` function. - * This module is intended to be imported into a taint-tracking query - * to extend `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -import semmle.python.web.bottle.General - -deprecated FunctionValue bottle_redirect() { result = theBottleModule().attr("redirect") } - -/** - * An argument to the `bottle.redirect` function. - */ -deprecated class BottleRedirect extends TaintSink { - override string toString() { result = "bottle.redirect" } - - BottleRedirect() { - exists(CallNode call | - bottle_redirect().getACall() = call and - this = call.getAnArg() - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } -} diff --git a/python/ql/lib/semmle/python/web/bottle/Request.qll b/python/ql/lib/semmle/python/web/bottle/Request.qll deleted file mode 100644 index 3de4748b30e..00000000000 --- a/python/ql/lib/semmle/python/web/bottle/Request.qll +++ /dev/null @@ -1,80 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.External -import semmle.python.web.Http -import semmle.python.web.bottle.General - -deprecated private Value theBottleRequestObject() { result = theBottleModule().attr("request") } - -deprecated class BottleRequestKind extends TaintKind { - BottleRequestKind() { this = "bottle.request" } - - override TaintKind getTaintOfAttribute(string name) { - result instanceof BottleFormsDict and - (name = "cookies" or name = "query" or name = "form") - or - result instanceof ExternalStringKind and - (name = "query_string" or name = "url_args") - or - result.(DictKind).getValue() instanceof FileUpload and - name = "files" - } -} - -deprecated private class RequestSource extends HttpRequestTaintSource { - RequestSource() { this.(ControlFlowNode).pointsTo(theBottleRequestObject()) } - - override predicate isSourceOf(TaintKind kind) { kind instanceof BottleRequestKind } -} - -deprecated class BottleFormsDict extends TaintKind { - BottleFormsDict() { this = "bottle.FormsDict" } - - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - /* Cannot use `getTaintOfAttribute(name)` as it wouldn't bind `name` */ - exists(string name | - fromnode = tonode.(AttrNode).getObject(name) and - result instanceof ExternalStringKind - | - name != "get" and name != "getunicode" and name != "getall" - ) - } - - override TaintKind getTaintOfMethodResult(string name) { - (name = "get" or name = "getunicode") and - result instanceof ExternalStringKind - or - name = "getall" and result.(SequenceKind).getItem() instanceof ExternalStringKind - } -} - -deprecated class FileUpload extends TaintKind { - FileUpload() { this = "bottle.FileUpload" } - - override TaintKind getTaintOfAttribute(string name) { - name = "filename" and result instanceof ExternalStringKind - or - name = "raw_filename" and result instanceof ExternalStringKind - or - name = "file" and result instanceof UntrustedFile - } -} - -deprecated class UntrustedFile extends TaintKind { - UntrustedFile() { this = "Untrusted file" } -} - -// -// TO DO.. File uploads -- Should check about file uploads for other frameworks as well. -// Move UntrustedFile to shared location -// -/** A parameter to a bottle request handler function */ -deprecated class BottleRequestParameter extends HttpRequestTaintSource { - BottleRequestParameter() { - exists(BottleRoute route | route.getANamedArgument() = this.(ControlFlowNode).getNode()) - } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "bottle handler function argument" } -} diff --git a/python/ql/lib/semmle/python/web/bottle/Response.qll b/python/ql/lib/semmle/python/web/bottle/Response.qll deleted file mode 100644 index f027c6be1a5..00000000000 --- a/python/ql/lib/semmle/python/web/bottle/Response.qll +++ /dev/null @@ -1,52 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted -import semmle.python.web.Http -import semmle.python.web.bottle.General - -/** - * A bottle.Response object - * This isn't really a "taint", but we use the value tracking machinery to - * track the flow of response objects. - */ -deprecated class BottleResponse extends TaintKind { - BottleResponse() { this = "bottle.response" } -} - -deprecated private Value theBottleResponseObject() { result = theBottleModule().attr("response") } - -deprecated class BottleResponseBodyAssignment extends HttpResponseTaintSink { - BottleResponseBodyAssignment() { - exists(DefinitionNode lhs | - lhs.getValue() = this and - lhs.(AttrNode).getObject("body").pointsTo(theBottleResponseObject()) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } -} - -deprecated class BottleHandlerFunctionResult extends HttpResponseTaintSink { - BottleHandlerFunctionResult() { - exists(BottleRoute route, Return ret | - ret.getScope() = route.getFunction() and - ret.getValue().getAFlowNode() = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } - - override string toString() { result = "bottle handler function result" } -} - -deprecated class BottleCookieSet extends CookieSet, CallNode { - BottleCookieSet() { - any(BottleResponse r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) - } - - override string toString() { result = CallNode.super.toString() } - - override ControlFlowNode getKey() { result = this.getArg(0) } - - override ControlFlowNode getValue() { result = this.getArg(1) } -} diff --git a/python/ql/lib/semmle/python/web/cherrypy/General.qll b/python/ql/lib/semmle/python/web/cherrypy/General.qll deleted file mode 100644 index 40becc70a50..00000000000 --- a/python/ql/lib/semmle/python/web/cherrypy/General.qll +++ /dev/null @@ -1,44 +0,0 @@ -import python -import semmle.python.web.Http - -deprecated module CherryPy { - FunctionValue expose() { result = Value::named("cherrypy.expose") } -} - -deprecated class CherryPyExposedFunction extends Function { - CherryPyExposedFunction() { - this.getADecorator().pointsTo(CherryPy::expose()) - or - this.getADecorator().(Call).getFunc().pointsTo(CherryPy::expose()) - } -} - -deprecated class CherryPyRoute extends CallNode { - CherryPyRoute() { - /* cherrypy.quickstart(root, script_name, config) */ - Value::named("cherrypy.quickstart").(FunctionValue).getACall() = this - or - /* cherrypy.tree.mount(root, script_name, config) */ - this.getFunction().(AttrNode).getObject("mount").pointsTo(Value::named("cherrypy.tree")) - } - - ClassValue getAppClass() { - this.getArg(0).pointsTo().getClass() = result - or - this.getArgByName("root").pointsTo().getClass() = result - } - - string getPath() { - exists(Value path | path = Value::forString(result) | - this.getArg(1).pointsTo(path) - or - this.getArgByName("script_name").pointsTo(path) - ) - } - - ClassValue getConfig() { - this.getArg(2).pointsTo().getClass() = result - or - this.getArgByName("config").pointsTo().getClass() = result - } -} diff --git a/python/ql/lib/semmle/python/web/cherrypy/Request.qll b/python/ql/lib/semmle/python/web/cherrypy/Request.qll deleted file mode 100644 index b3c096f8bdd..00000000000 --- a/python/ql/lib/semmle/python/web/cherrypy/Request.qll +++ /dev/null @@ -1,41 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -import semmle.python.web.Http -import semmle.python.web.cherrypy.General - -/** The cherrypy.request local-proxy object */ -deprecated class CherryPyRequest extends TaintKind { - CherryPyRequest() { this = "cherrypy.request" } - - override TaintKind getTaintOfAttribute(string name) { - name = "params" and result instanceof ExternalStringDictKind - or - name = "cookie" and result instanceof UntrustedCookie - } - - override TaintKind getTaintOfMethodResult(string name) { - name in ["getHeader", "getCookie", "getUser", "getPassword"] and - result instanceof ExternalStringKind - } -} - -deprecated class CherryPyExposedFunctionParameter extends HttpRequestTaintSource { - CherryPyExposedFunctionParameter() { - exists(Parameter p | - p = any(CherryPyExposedFunction f).getAnArg() and - not p.isSelf() and - p.asName().getAFlowNode() = this - ) - } - - override string toString() { result = "CherryPy handler function parameter" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } -} - -deprecated class CherryPyRequestSource extends HttpRequestTaintSource { - CherryPyRequestSource() { this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) } - - override predicate isSourceOf(TaintKind kind) { kind instanceof CherryPyRequest } -} diff --git a/python/ql/lib/semmle/python/web/cherrypy/Response.qll b/python/ql/lib/semmle/python/web/cherrypy/Response.qll deleted file mode 100644 index 124a9f9b7d0..00000000000 --- a/python/ql/lib/semmle/python/web/cherrypy/Response.qll +++ /dev/null @@ -1,18 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted -import semmle.python.web.Http -import semmle.python.web.cherrypy.General - -deprecated class CherryPyExposedFunctionResult extends HttpResponseTaintSink { - CherryPyExposedFunctionResult() { - exists(Return ret | - ret.getScope() instanceof CherryPyExposedFunction and - ret.getValue().getAFlowNode() = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } - - override string toString() { result = "cherrypy handler function result" } -} diff --git a/python/ql/lib/semmle/python/web/client/Requests.qll b/python/ql/lib/semmle/python/web/client/Requests.qll deleted file mode 100644 index 9adf2c8120f..00000000000 --- a/python/ql/lib/semmle/python/web/client/Requests.qll +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Modeling outgoing HTTP requests using the `requests` package - * https://pypi.org/project/requests/ - */ - -import python -private import semmle.python.web.Http - -deprecated class RequestsHttpRequest extends Client::HttpRequest, CallNode { - CallableValue func; - string method; - - RequestsHttpRequest() { - method = httpVerbLower() and - func = Module::named("requests").attr(method) and - this = func.getACall() - } - - override ControlFlowNode getAUrlPart() { result = func.getNamedArgumentForCall(this, "url") } - - override string getMethodUpper() { result = method.toUpperCase() } -} diff --git a/python/ql/lib/semmle/python/web/client/StdLib.qll b/python/ql/lib/semmle/python/web/client/StdLib.qll deleted file mode 100644 index b8a533c410f..00000000000 --- a/python/ql/lib/semmle/python/web/client/StdLib.qll +++ /dev/null @@ -1,55 +0,0 @@ -import python -private import semmle.python.web.Http - -deprecated ClassValue httpConnectionClass() { - // Python 2 - result = Value::named("httplib.HTTPConnection") - or - result = Value::named("httplib.HTTPSConnection") - or - // Python 3 - result = Value::named("http.client.HTTPConnection") - or - result = Value::named("http.client.HTTPSConnection") - or - // six - result = Value::named("six.moves.http_client.HTTPConnection") - or - result = Value::named("six.moves.http_client.HTTPSConnection") -} - -deprecated class HttpConnectionHttpRequest extends Client::HttpRequest, CallNode { - CallNode constructor_call; - CallableValue func; - - HttpConnectionHttpRequest() { - exists(ClassValue cls, AttrNode call_origin, Value constructor_call_value | - cls = httpConnectionClass() and - func = cls.lookup("request") and - this = func.getACall() and - // since you can do `r = conn.request; r('GET', path)`, we need to find the origin - this.getFunction().pointsTo(_, _, call_origin) and - // Since HTTPSConnection is a subtype of HTTPConnection, up until this point, `cls` could be either class, - // because `HTTPSConnection.request == HTTPConnection.request`. To avoid generating 2 results, we filter - // on the actual class used as the constructor - call_origin.getObject().pointsTo(_, constructor_call_value, constructor_call) and - cls = constructor_call_value.getClass() and - constructor_call = cls.getACall() - ) - } - - override ControlFlowNode getAUrlPart() { - result = func.getNamedArgumentForCall(this, "url") - or - result = constructor_call.getArg(0) - or - result = constructor_call.getArgByName("host") - } - - override string getMethodUpper() { - exists(string method | - result = method.toUpperCase() and - func.getNamedArgumentForCall(this, "method").pointsTo(Value::forString(method)) - ) - } -} diff --git a/python/ql/lib/semmle/python/web/django/Db.qll b/python/ql/lib/semmle/python/web/django/Db.qll deleted file mode 100644 index bb089f5f0fe..00000000000 --- a/python/ql/lib/semmle/python/web/django/Db.qll +++ /dev/null @@ -1,50 +0,0 @@ -import python -import semmle.python.security.injection.Sql - -/** - * A taint kind representing a django cursor object. - */ -deprecated class DjangoDbCursor extends DbCursor { - DjangoDbCursor() { this = "django.db.connection.cursor" } -} - -deprecated private Value theDjangoConnectionObject() { - result = Value::named("django.db.connection") -} - -/** - * A kind of taint source representing sources of django cursor objects. - */ -deprecated class DjangoDbCursorSource extends DbConnectionSource { - DjangoDbCursorSource() { - exists(AttrNode cursor | - this.(CallNode).getFunction() = cursor and - cursor.getObject("cursor").pointsTo(theDjangoConnectionObject()) - ) - } - - override string toString() { result = "django.db.connection.cursor" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbCursor } -} - -deprecated ClassValue theDjangoRawSqlClass() { - result = Value::named("django.db.models.expressions.RawSQL") -} - -/** - * A sink of taint on calls to `django.db.models.expressions.RawSQL`. This - * allows arbitrary SQL statements to be executed, which is a security risk. - */ -deprecated class DjangoRawSqlSink extends SqlInjectionSink { - DjangoRawSqlSink() { - exists(CallNode call | - call = theDjangoRawSqlClass().getACall() and - this = call.getArg(0) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "django.db.models.expressions.RawSQL(sink,...)" } -} diff --git a/python/ql/lib/semmle/python/web/django/General.qll b/python/ql/lib/semmle/python/web/django/General.qll deleted file mode 100644 index 1b179b35f9a..00000000000 --- a/python/ql/lib/semmle/python/web/django/General.qll +++ /dev/null @@ -1,136 +0,0 @@ -import python -import semmle.python.regex -import semmle.python.web.Http - -// TODO: Since django uses `path = partial(...)`, our analysis doesn't understand this is -// a FunctionValue, so we can't use `FunctionValue.getArgumentForCall` -// https://github.com/django/django/blob/master/django/urls/conf.py#L76 -abstract deprecated class DjangoRoute extends CallNode { - DjangoViewHandler getViewHandler() { - result = view_handler_from_view_arg(this.getArg(1)) - or - result = view_handler_from_view_arg(this.getArgByName("view")) - } - - abstract string getANamedArgument(); - - /** - * Get the number of positional arguments that will be passed to the view. - * Will only return a result if there are no named arguments. - */ - abstract int getNumPositionalArguments(); -} - -/** - * For function based views -- also see `DjangoClassBasedViewHandler` - * https://docs.djangoproject.com/en/1.11/topics/http/views/ - * https://docs.djangoproject.com/en/3.0/topics/http/views/ - */ -deprecated class DjangoViewHandler extends PythonFunctionValue { - /** Gets the index of the 'request' argument */ - int getRequestArgIndex() { result = 0 } -} - -/** - * Class based views - * https://docs.djangoproject.com/en/1.11/topics/class-based-views/ - * https://docs.djangoproject.com/en/3.0/topics/class-based-views/ - */ -deprecated private class DjangoViewClass extends ClassValue { - DjangoViewClass() { - Value::named("django.views.generic.View") = this.getASuperType() - or - Value::named("django.views.View") = this.getASuperType() - } -} - -deprecated class DjangoClassBasedViewHandler extends DjangoViewHandler { - DjangoClassBasedViewHandler() { exists(DjangoViewClass cls | cls.lookup(httpVerbLower()) = this) } - - override int getRequestArgIndex() { - // due to `self` being the first parameter - result = 1 - } -} - -/** - * Gets the function that will handle requests when `view_arg` is used as the view argument to a - * django route. That is, this methods handles Class-based Views and its `as_view()` function. - */ -deprecated private DjangoViewHandler view_handler_from_view_arg(ControlFlowNode view_arg) { - // Function-based view - result = view_arg.pointsTo() - or - // Class-based view - exists(ClassValue cls | - cls = view_arg.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo() and - result = cls.lookup(httpVerbLower()) - ) -} - -// We need this "dummy" class, since otherwise the regex argument would not be considered -// a regex (RegexString is abstract) -deprecated class DjangoRouteRegex extends RegexString { - DjangoRouteRegex() { exists(DjangoRegexRoute route | route.getRouteArg() = this.getAFlowNode()) } -} - -deprecated class DjangoRegexRoute extends DjangoRoute { - ControlFlowNode route; - - DjangoRegexRoute() { - exists(FunctionValue route_maker | - // Django 1.x: https://docs.djangoproject.com/en/1.11/ref/urls/#django.conf.urls.url - Value::named("django.conf.urls.url") = route_maker and - route_maker.getArgumentForCall(this, 0) = route - ) - or - // Django 2.x and 3.x: https://docs.djangoproject.com/en/3.0/ref/urls/#re-path - this = Value::named("django.urls.re_path").getACall() and - ( - route = this.getArg(0) - or - route = this.getArgByName("route") - ) - } - - ControlFlowNode getRouteArg() { result = route } - - override string getANamedArgument() { - exists(DjangoRouteRegex regex | regex.getAFlowNode() = route | - result = regex.getGroupName(_, _) - ) - } - - override int getNumPositionalArguments() { - not exists(this.getANamedArgument()) and - exists(DjangoRouteRegex regex | regex.getAFlowNode() = route | - result = count(regex.getGroupNumber(_, _)) - ) - } -} - -deprecated class DjangoPathRoute extends DjangoRoute { - ControlFlowNode route; - - DjangoPathRoute() { - // Django 2.x and 3.x: https://docs.djangoproject.com/en/3.0/ref/urls/#path - this = Value::named("django.urls.path").getACall() and - ( - route = this.getArg(0) - or - route = this.getArgByName("route") - ) - } - - override string getANamedArgument() { - // regexp taken from django: - // https://github.com/django/django/blob/7d1bf29977bb368d7c28e7c6eb146db3b3009ae7/django/urls/resolvers.py#L199 - exists(StrConst route_str, string match | - route_str = route.getNode() and - match = route_str.getText().regexpFind("<(?:(?[^>:]+):)?(?\\w+)>", _, _) and - result = match.regexpCapture("<(?:(?[^>:]+):)?(?\\w+)>", 2) - ) - } - - override int getNumPositionalArguments() { none() } -} diff --git a/python/ql/lib/semmle/python/web/django/Model.qll b/python/ql/lib/semmle/python/web/django/Model.qll deleted file mode 100644 index 944eec4f799..00000000000 --- a/python/ql/lib/semmle/python/web/django/Model.qll +++ /dev/null @@ -1,69 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -import semmle.python.web.Http -import semmle.python.security.injection.Sql - -/** A django model class */ -deprecated class DjangoModel extends ClassValue { - DjangoModel() { Value::named("django.db.models.Model") = this.getASuperType() } -} - -/** A "taint" for django database tables */ -deprecated class DjangoDbTableObjects extends TaintKind { - DjangoDbTableObjects() { this = "django.db.models.Model.objects" } - - override TaintKind getTaintOfMethodResult(string name) { - result = this and - name in [ - "filter", "exclude", "none", "all", "union", "intersection", "difference", "select_related", - "prefetch_related", "extra", "defer", "only", "annotate", "using", "select_for_update", - "raw", "order_by", "reverse", "distinct", "values", "values_list", "dates", "datetimes" - ] - } -} - -/** Django model objects, which are sources of django database table "taint" */ -deprecated class DjangoModelObjects extends TaintSource { - DjangoModelObjects() { - this.(AttrNode).isLoad() and this.(AttrNode).getObject("objects").pointsTo(any(DjangoModel m)) - } - - override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbTableObjects } - - override string toString() { result = "django.db.models.Model.objects" } -} - -/** - * A call to the `raw` method on a django model. This allows a raw SQL query - * to be sent to the database, which is a security risk. - */ -deprecated class DjangoModelRawCall extends SqlInjectionSink { - DjangoModelRawCall() { - exists(CallNode raw_call, ControlFlowNode queryset | this = raw_call.getArg(0) | - raw_call.getFunction().(AttrNode).getObject("raw") = queryset and - any(DjangoDbTableObjects objs).taints(queryset) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "django.models.QuerySet.raw(sink,...)" } -} - -/** - * A call to the `extra` method on a django model. This allows a raw SQL query - * to be sent to the database, which is a security risk. - */ -deprecated class DjangoModelExtraCall extends SqlInjectionSink { - DjangoModelExtraCall() { - exists(CallNode extra_call, ControlFlowNode queryset | this = extra_call.getArg(0) | - extra_call.getFunction().(AttrNode).getObject("extra") = queryset and - any(DjangoDbTableObjects objs).taints(queryset) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "django.models.QuerySet.extra(sink,...)" } -} diff --git a/python/ql/lib/semmle/python/web/django/Redirect.qll b/python/ql/lib/semmle/python/web/django/Redirect.qll deleted file mode 100644 index 0319f18190f..00000000000 --- a/python/ql/lib/semmle/python/web/django/Redirect.qll +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Provides class representing the `django.redirect` function. - * This module is intended to be imported into a taint-tracking query - * to extend `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -private import semmle.python.web.django.Shared -private import semmle.python.web.Http - -/** - * The URL argument for a call to the `django.shortcuts.redirect` function. - */ -deprecated class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink { - override string toString() { result = "DjangoShortcutsRedirectSink" } - - DjangoShortcutsRedirectSink() { - this = Value::named("django.shortcuts.redirect").(FunctionValue).getArgumentForCall(_, 0) - } -} - -/** - * The URL argument when instantiating a Django Redirect Response. - */ -deprecated class DjangoRedirectResponseSink extends HttpRedirectTaintSink { - DjangoRedirectResponseSink() { - exists(CallNode call | call = any(DjangoRedirectResponseClass cls).getACall() | - this = call.getArg(0) - or - this = call.getArgByName("redirect_to") - ) - } - - override string toString() { result = "DjangoRedirectResponseSink" } -} diff --git a/python/ql/lib/semmle/python/web/django/Request.qll b/python/ql/lib/semmle/python/web/django/Request.qll deleted file mode 100644 index 7e7358595e5..00000000000 --- a/python/ql/lib/semmle/python/web/django/Request.qll +++ /dev/null @@ -1,78 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http -import semmle.python.web.django.General - -/** A django.request.HttpRequest object */ -deprecated class DjangoRequest extends TaintKind { - DjangoRequest() { this = "django.request.HttpRequest" } - - override TaintKind getTaintOfAttribute(string name) { - (name = "GET" or name = "POST") and - result instanceof DjangoQueryDict - } - - override TaintKind getTaintOfMethodResult(string name) { - (name = "body" or name = "path") and - result instanceof ExternalStringKind - } -} - -/* Helper for getTaintForStep() */ -pragma[noinline] -deprecated private predicate subscript_taint(SubscriptNode sub, ControlFlowNode obj, TaintKind kind) { - sub.getObject() = obj and - kind instanceof ExternalStringKind -} - -/** A django.request.QueryDict object */ -deprecated class DjangoQueryDict extends TaintKind { - DjangoQueryDict() { this = "django.http.request.QueryDict" } - - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - this.taints(fromnode) and - subscript_taint(tonode, fromnode, result) - } - - override TaintKind getTaintOfMethodResult(string name) { - name = "get" and result instanceof ExternalStringKind - } -} - -/** A Django request parameter */ -deprecated class DjangoRequestSource extends HttpRequestTaintSource { - DjangoRequestSource() { - exists(DjangoRoute route, DjangoViewHandler view, int request_arg_index | - route.getViewHandler() = view and - request_arg_index = view.getRequestArgIndex() and - this = view.getScope().getArg(request_arg_index).asName().getAFlowNode() - ) - } - - override string toString() { result = "Django request source" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoRequest } -} - -/** An argument specified in a url routing table */ -deprecated class DjangoRequestParameter extends HttpRequestTaintSource { - DjangoRequestParameter() { - exists(DjangoRoute route, Function f, DjangoViewHandler view, int request_arg_index | - route.getViewHandler() = view and - request_arg_index = view.getRequestArgIndex() and - f = view.getScope() - | - this.(ControlFlowNode).getNode() = f.getArgByName(route.getANamedArgument()) - or - exists(int i | i >= 0 | - i < route.getNumPositionalArguments() and - // +1 because first argument is always the request - this.(ControlFlowNode).getNode() = f.getArg(request_arg_index + 1 + i) - ) - ) - } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "django.http.request.parameter" } -} diff --git a/python/ql/lib/semmle/python/web/django/Response.qll b/python/ql/lib/semmle/python/web/django/Response.qll deleted file mode 100644 index 3444884dd32..00000000000 --- a/python/ql/lib/semmle/python/web/django/Response.qll +++ /dev/null @@ -1,79 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -private import semmle.python.web.django.Shared -private import semmle.python.web.Http - -/** INTERNAL class used for tracking a django response object. */ -deprecated private class DjangoResponseKind extends TaintKind { - DjangoResponseKind() { this = "django.response.HttpResponse" } -} - -/** INTERNAL taint-source used for tracking a django response object. */ -deprecated private class DjangoResponseSource extends TaintSource { - DjangoResponseSource() { exists(DjangoContentResponseClass cls | cls.getACall() = this) } - - override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponseKind } - - override string toString() { result = "django.http.response.HttpResponse" } -} - -/** A write to a django response, which is vulnerable to external data (xss) */ -deprecated class DjangoResponseWrite extends HttpResponseTaintSink { - DjangoResponseWrite() { - exists(AttrNode meth, CallNode call | - call.getFunction() = meth and - any(DjangoResponseKind response).taints(meth.getObject("write")) and - this = call.getArg(0) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } - - override string toString() { result = "django.Response.write(...)" } -} - -/** - * An argument to initialization of a django response. - */ -deprecated class DjangoResponseContent extends HttpResponseTaintSink { - DjangoContentResponseClass cls; - CallNode call; - - DjangoResponseContent() { - call = cls.getACall() and - this = cls.getContentArg(call) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } - - override string toString() { result = "django.Response(...)" } -} - -/** - * An argument to initialization of a django response, which is vulnerable to external data (XSS). - */ -deprecated class DjangoResponseContentXSSVulnerable extends DjangoResponseContent { - override DjangoXSSVulnerableResponseClass cls; - - DjangoResponseContentXSSVulnerable() { - not exists(cls.getContentTypeArg(call)) - or - exists(StringValue s | - cls.getContentTypeArg(call).pointsTo(s) and - s.getText().matches("text/html%") - ) - } -} - -deprecated class DjangoCookieSet extends CookieSet, CallNode { - DjangoCookieSet() { - any(DjangoResponseKind r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) - } - - override string toString() { result = CallNode.super.toString() } - - override ControlFlowNode getKey() { result = this.getArg(0) } - - override ControlFlowNode getValue() { result = this.getArg(1) } -} diff --git a/python/ql/lib/semmle/python/web/django/Sanitizers.qll b/python/ql/lib/semmle/python/web/django/Sanitizers.qll deleted file mode 100644 index e1694a1c481..00000000000 --- a/python/ql/lib/semmle/python/web/django/Sanitizers.qll +++ /dev/null @@ -1,6 +0,0 @@ -import python -/* - * Sanitizers - * No django sanitizers implemented yet. - */ - diff --git a/python/ql/lib/semmle/python/web/django/Shared.qll b/python/ql/lib/semmle/python/web/django/Shared.qll deleted file mode 100644 index bc156249d25..00000000000 --- a/python/ql/lib/semmle/python/web/django/Shared.qll +++ /dev/null @@ -1,72 +0,0 @@ -import python - -/** A class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */ -deprecated class DjangoRedirectResponseClass extends ClassValue { - DjangoRedirectResponseClass() { - exists(ClassValue redirect_base | - // version 1.x - redirect_base = Value::named("django.http.response.HttpResponseRedirectBase") - or - // version 2.x and 3.x - redirect_base = Value::named("django.http.HttpResponseRedirectBase") - | - this.getASuperType() = redirect_base - ) - } -} - -/** - * A class that is a Django Response, which can contain content. - * A subclass of `django.http.HttpResponse` that is not a `DjangoRedirectResponseClass`. - */ -deprecated class DjangoContentResponseClass extends ClassValue { - ClassValue base; - - DjangoContentResponseClass() { - ( - // version 1.x - base = Value::named("django.http.response.HttpResponse") - or - // version 2.x and 3.x - // https://docs.djangoproject.com/en/2.2/ref/request-response/#httpresponse-objects - base = Value::named("django.http.HttpResponse") - ) and - this.getASuperType() = base - } - - // The reason these two methods are defined in this class (and not in the Sink - // definition that uses this class), is that if we were to add support for - // `django.http.response.HttpResponseNotAllowed` it would make much more sense to add - // the custom logic in this class (or subclass), than to handle all of it in the sink - // definition. - /** Gets the `content` argument of a `call` to the constructor */ - ControlFlowNode getContentArg(CallNode call) { none() } - - /** Gets the `content_type` argument of a `call` to the constructor */ - ControlFlowNode getContentTypeArg(CallNode call) { none() } -} - -/** A class that is a Django Response, and is vulnerable to XSS. */ -deprecated class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass { - DjangoXSSVulnerableResponseClass() { - // We want to avoid FPs on subclasses that are not exposed to XSS, for example `JsonResponse`. - // The easiest way is to disregard any subclass that has a special `__init__` method. - // It's not guaranteed to remove all FPs, or not to generate FNs, but compared to our - // previous implementation that would treat 0-th argument to _any_ subclass as a sink, - // this gets us much closer to reality. - this.lookup("__init__") = base.lookup("__init__") and - not this instanceof DjangoRedirectResponseClass - } - - override ControlFlowNode getContentArg(CallNode call) { - result = call.getArg(0) - or - result = call.getArgByName("content") - } - - override ControlFlowNode getContentTypeArg(CallNode call) { - result = call.getArg(1) - or - result = call.getArgByName("content_type") - } -} diff --git a/python/ql/lib/semmle/python/web/falcon/General.qll b/python/ql/lib/semmle/python/web/falcon/General.qll deleted file mode 100644 index 5f9cce57611..00000000000 --- a/python/ql/lib/semmle/python/web/falcon/General.qll +++ /dev/null @@ -1,46 +0,0 @@ -import python -import semmle.python.web.Http - -/** Gets the falcon API class */ -deprecated ClassValue theFalconAPIClass() { result = Value::named("falcon.API") } - -/** Holds if `route` is routed to `resource` */ -deprecated private predicate api_route( - CallNode route_call, ControlFlowNode route, ClassValue resource -) { - route_call.getFunction().(AttrNode).getObject("add_route").pointsTo().getClass() = - theFalconAPIClass() and - route_call.getArg(0) = route and - route_call.getArg(1).pointsTo().getClass() = resource -} - -deprecated private predicate route(FalconRoute route, Function target, string funcname) { - route.getResourceClass().lookup("on_" + funcname).(FunctionValue).getScope() = target -} - -deprecated class FalconRoute extends ControlFlowNode { - FalconRoute() { api_route(this, _, _) } - - string getUrl() { - exists(StrConst url | - api_route(this, url.getAFlowNode(), _) and - result = url.getText() - ) - } - - ClassValue getResourceClass() { api_route(this, _, result) } - - FalconHandlerFunction getHandlerFunction(string method) { route(this, result, method) } -} - -deprecated class FalconHandlerFunction extends Function { - FalconHandlerFunction() { route(_, this, _) } - - private string methodName() { route(_, this, result) } - - string getMethod() { result = this.methodName().toUpperCase() } - - Parameter getRequest() { result = this.getArg(1) } - - Parameter getResponse() { result = this.getArg(2) } -} diff --git a/python/ql/lib/semmle/python/web/falcon/Request.qll b/python/ql/lib/semmle/python/web/falcon/Request.qll deleted file mode 100644 index ac4c92f3ad0..00000000000 --- a/python/ql/lib/semmle/python/web/falcon/Request.qll +++ /dev/null @@ -1,37 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http -import semmle.python.web.falcon.General - -/** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */ -deprecated class FalconRequest extends TaintKind { - FalconRequest() { this = "falcon.request" } - - override TaintKind getTaintOfAttribute(string name) { - name = "env" and result instanceof WsgiEnvironment - or - result instanceof ExternalStringKind and - name in ["uri", "url", "forwarded_uri", "relative_uri", "query_string"] - or - result instanceof ExternalStringDictKind and - (name = "cookies" or name = "params") - or - name = "stream" and result instanceof ExternalFileObject - } - - override TaintKind getTaintOfMethodResult(string name) { - name = "get_param" and result instanceof ExternalStringKind - or - name = "get_param_as_json" and result instanceof ExternalJsonKind - or - name = "get_param_as_list" and result instanceof ExternalStringSequenceKind - } -} - -deprecated class FalconRequestParameter extends HttpRequestTaintSource { - FalconRequestParameter() { - exists(FalconHandlerFunction f | f.getRequest() = this.(ControlFlowNode).getNode()) - } - - override predicate isSourceOf(TaintKind k) { k instanceof FalconRequest } -} diff --git a/python/ql/lib/semmle/python/web/falcon/Response.qll b/python/ql/lib/semmle/python/web/falcon/Response.qll deleted file mode 100644 index ae5562b6432..00000000000 --- a/python/ql/lib/semmle/python/web/falcon/Response.qll +++ /dev/null @@ -1,28 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http -import semmle.python.web.falcon.General - -/** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */ -deprecated class FalconResponse extends TaintKind { - FalconResponse() { this = "falcon.response" } -} - -/** Only used internally to track the response parameter */ -deprecated private class FalconResponseParameter extends TaintSource { - FalconResponseParameter() { - exists(FalconHandlerFunction f | f.getResponse() = this.(ControlFlowNode).getNode()) - } - - override predicate isSourceOf(TaintKind k) { k instanceof FalconResponse } -} - -deprecated class FalconResponseBodySink extends HttpResponseTaintSink { - FalconResponseBodySink() { - exists(AttrNode attr | any(FalconResponse f).taints(attr.getObject("body")) | - attr.(DefinitionNode).getValue() = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } -} diff --git a/python/ql/lib/semmle/python/web/flask/General.qll b/python/ql/lib/semmle/python/web/flask/General.qll deleted file mode 100644 index cc4d992f9ff..00000000000 --- a/python/ql/lib/semmle/python/web/flask/General.qll +++ /dev/null @@ -1,104 +0,0 @@ -import python -import semmle.python.web.Http -import semmle.python.web.flask.Response - -/** Gets the flask app class */ -deprecated ClassValue theFlaskClass() { result = Value::named("flask.Flask") } - -/** Gets the flask MethodView class */ -deprecated ClassValue theFlaskMethodViewClass() { result = Value::named("flask.views.MethodView") } - -deprecated ClassValue theFlaskReponseClass() { result = Value::named("flask.Response") } - -/** - * Holds if `route` is routed to `func` - * by decorating `func` with `app.route(route)` - */ -deprecated predicate app_route(ControlFlowNode route, Function func) { - exists(CallNode route_call, CallNode decorator_call | - route_call.getFunction().(AttrNode).getObject("route").pointsTo().getClass() = theFlaskClass() and - decorator_call.getFunction() = route_call and - route_call.getArg(0) = route and - decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func - ) -} - -/* Helper for add_url_rule */ -deprecated private predicate add_url_rule_call(ControlFlowNode regex, ControlFlowNode callable) { - exists(CallNode call | - call.getFunction().(AttrNode).getObject("add_url_rule").pointsTo().getClass() = theFlaskClass() and - regex = call.getArg(0) - | - callable = call.getArg(2) or - callable = call.getArgByName("view_func") - ) -} - -/** Holds if urls matching `regex` are routed to `func` */ -deprecated predicate add_url_rule(ControlFlowNode regex, Function func) { - exists(ControlFlowNode callable | add_url_rule_call(regex, callable) | - exists(PythonFunctionValue f | f.getScope() = func and callable.pointsTo(f)) - or - /* MethodView.as_view() */ - exists(MethodViewClass view_cls | view_cls.asTaint().taints(callable) | - func = view_cls.lookup(httpVerbLower()).(FunctionValue).getScope() - ) - /* TODO: -- Handle Views that aren't MethodViews */ - ) -} - -/** - * Holds if urls matching `regex` are routed to `func` using - * any of flask's routing mechanisms. - */ -deprecated predicate flask_routing(ControlFlowNode regex, Function func) { - app_route(regex, func) - or - add_url_rule(regex, func) -} - -/** A class that extends flask.views.MethodView */ -deprecated private class MethodViewClass extends ClassValue { - MethodViewClass() { this.getASuperType() = theFlaskMethodViewClass() } - - /* As we are restricted to strings for taint kinds, we need to map these classes to strings. */ - string taintString() { result = "flask/" + this.getQualifiedName() + ".as.view" } - - /* As we are restricted to strings for taint kinds, we need to map these classes to strings. */ - TaintKind asTaint() { result = this.taintString() } -} - -deprecated private class MethodViewTaint extends TaintKind { - MethodViewTaint() { any(MethodViewClass cls).taintString() = this } -} - -/** A source of method view "taint"s. */ -deprecated private class AsView extends TaintSource { - AsView() { - exists(ClassValue view_class | - view_class.getASuperType() = theFlaskMethodViewClass() and - this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class) - ) - } - - override string toString() { result = "flask.MethodView.as_view()" } - - override predicate isSourceOf(TaintKind kind) { - exists(MethodViewClass view_class | - kind = view_class.asTaint() and - this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class) - ) - } -} - -deprecated class FlaskCookieSet extends CookieSet, CallNode { - FlaskCookieSet() { - any(FlaskResponseTaintKind t).taints(this.getFunction().(AttrNode).getObject("set_cookie")) - } - - override string toString() { result = CallNode.super.toString() } - - override ControlFlowNode getKey() { result = this.getArg(0) } - - override ControlFlowNode getValue() { result = this.getArg(1) } -} diff --git a/python/ql/lib/semmle/python/web/flask/Redirect.qll b/python/ql/lib/semmle/python/web/flask/Redirect.qll deleted file mode 100644 index f178c2520ea..00000000000 --- a/python/ql/lib/semmle/python/web/flask/Redirect.qll +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Provides class representing the `flask.redirect` function. - * This module is intended to be imported into a taint-tracking query - * to extend `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -import semmle.python.web.flask.General - -deprecated FunctionValue flask_redirect() { result = Value::named("flask.redirect") } - -/** - * Represents an argument to the `flask.redirect` function. - */ -deprecated class FlaskRedirect extends HttpRedirectTaintSink { - override string toString() { result = "flask.redirect" } - - FlaskRedirect() { - exists(CallNode call | - flask_redirect().getACall() = call and - this = call.getAnArg() - ) - } -} diff --git a/python/ql/lib/semmle/python/web/flask/Request.qll b/python/ql/lib/semmle/python/web/flask/Request.qll deleted file mode 100644 index ea9a59dc45e..00000000000 --- a/python/ql/lib/semmle/python/web/flask/Request.qll +++ /dev/null @@ -1,80 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http -import semmle.python.web.flask.General - -deprecated private Value theFlaskRequestObject() { result = Value::named("flask.request") } - -/** Holds if `attr` is an access of attribute `name` of the flask request object */ -deprecated private predicate flask_request_attr(AttrNode attr, string name) { - attr.isLoad() and - attr.getObject(name).pointsTo(theFlaskRequestObject()) -} - -/** Source of external data from a flask request */ -deprecated class FlaskRequestData extends HttpRequestTaintSource { - FlaskRequestData() { - not this instanceof FlaskRequestArgs and - exists(string name | flask_request_attr(this, name) | - name in ["path", "full_path", "base_url", "url"] - ) - } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "flask.request" } -} - -/** Source of dictionary whose values are externally controlled */ -deprecated class FlaskRequestArgs extends HttpRequestTaintSource { - FlaskRequestArgs() { - exists(string attr | flask_request_attr(this, attr) | - attr in ["args", "form", "values", "files", "headers", "json"] - ) - } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - - override string toString() { result = "flask.request.args" } -} - -/** Source of dictionary whose values are externally controlled */ -deprecated class FlaskRequestJson extends HttpRequestTaintSource { - FlaskRequestJson() { flask_request_attr(this, "json") } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalJsonKind } - - override string toString() { result = "flask.request.json" } -} - -/** - * A parameter to a flask request handler, that can capture a part of the URL (as specified in - * the url-pattern of a route). - * - * For example, the `name` parameter in: - * ``` - * @app.route('/hello/') - * def hello(name): - * ``` - */ -deprecated class FlaskRoutedParameter extends HttpRequestTaintSource { - FlaskRoutedParameter() { - exists(string name, Function func, StrConst url_pattern | - this.(ControlFlowNode).getNode() = func.getArgByName(name) and - flask_routing(url_pattern.getAFlowNode(), func) and - exists(string match | - match = url_pattern.getS().regexpFind(werkzeug_rule_re(), _, _) and - name = match.regexpCapture(werkzeug_rule_re(), 4) - ) - ) - } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } -} - -deprecated private string werkzeug_rule_re() { - // since flask uses werkzeug internally, we are using its routing rules from - // https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151 - result = - "(?[^<]*)<(?:(?[a-zA-Z_][a-zA-Z0-9_]*)(?:\\((?.*?)\\))?\\:)?(?[a-zA-Z_][a-zA-Z0-9_]*)>" -} diff --git a/python/ql/lib/semmle/python/web/flask/Response.qll b/python/ql/lib/semmle/python/web/flask/Response.qll deleted file mode 100644 index 1e489c56b46..00000000000 --- a/python/ql/lib/semmle/python/web/flask/Response.qll +++ /dev/null @@ -1,55 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -import semmle.python.web.flask.General - -/** - * A flask response, which is vulnerable to any sort of - * http response malice. - */ -deprecated class FlaskRoutedResponse extends HttpResponseTaintSink { - FlaskRoutedResponse() { - exists(PythonFunctionValue response | - flask_routing(_, response.getScope()) and - this = response.getAReturnedNode() - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } - - override string toString() { result = "flask.routed.response" } -} - -deprecated class FlaskResponseArgument extends HttpResponseTaintSink { - FlaskResponseArgument() { - exists(CallNode call | - ( - call.getFunction().pointsTo(theFlaskReponseClass()) - or - call.getFunction().pointsTo(Value::named("flask.make_response")) - ) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } - - override string toString() { result = "flask.response.argument" } -} - -deprecated class FlaskResponseTaintKind extends TaintKind { - FlaskResponseTaintKind() { this = "flask.Response" } -} - -deprecated class FlaskResponseConfiguration extends TaintTracking::Configuration { - FlaskResponseConfiguration() { this = "Flask response configuration" } - - override predicate isSource(DataFlow::Node node, TaintKind kind) { - kind instanceof FlaskResponseTaintKind and - ( - node.asCfgNode().(CallNode).getFunction().pointsTo(theFlaskReponseClass()) - or - node.asCfgNode().(CallNode).getFunction().pointsTo(Value::named("flask.make_response")) - ) - } -} diff --git a/python/ql/lib/semmle/python/web/pyramid/Redirect.qll b/python/ql/lib/semmle/python/web/pyramid/Redirect.qll deleted file mode 100644 index 852df8cf422..00000000000 --- a/python/ql/lib/semmle/python/web/pyramid/Redirect.qll +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Provides class representing the `pyramid.redirect` function. - * This module is intended to be imported into a taint-tracking query - * to extend `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -import semmle.python.web.Http - -deprecated private ClassValue redirectClass() { - exists(ModuleValue ex | ex.getName() = "pyramid.httpexceptions" | - ex.attr("HTTPFound") = result - or - ex.attr("HTTPTemporaryRedirect") = result - ) -} - -/** - * Represents an argument to the `tornado.redirect` function. - */ -deprecated class PyramidRedirect extends HttpRedirectTaintSink { - override string toString() { result = "pyramid.redirect" } - - PyramidRedirect() { - exists(CallNode call | call.getFunction().pointsTo(redirectClass()) | - call.getArg(0) = this - or - call.getArgByName("location") = this - ) - } -} diff --git a/python/ql/lib/semmle/python/web/pyramid/Request.qll b/python/ql/lib/semmle/python/web/pyramid/Request.qll deleted file mode 100644 index df84cc84440..00000000000 --- a/python/ql/lib/semmle/python/web/pyramid/Request.qll +++ /dev/null @@ -1,25 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http -private import semmle.python.web.webob.Request -private import semmle.python.web.pyramid.View - -deprecated class PyramidRequest extends BaseWebobRequest { - PyramidRequest() { this = "pyramid.request" } - - override ClassValue getType() { result = Value::named("pyramid.request.Request") } -} - -/** Source of pyramid request objects */ -deprecated class PyramidViewArgument extends HttpRequestTaintSource { - PyramidViewArgument() { - exists(Function view_func | - is_pyramid_view_function(view_func) and - this.(ControlFlowNode).getNode() = view_func.getArg(0) - ) - } - - override predicate isSourceOf(TaintKind kind) { kind instanceof PyramidRequest } - - override string toString() { result = "pyramid.view.argument" } -} diff --git a/python/ql/lib/semmle/python/web/pyramid/Response.qll b/python/ql/lib/semmle/python/web/pyramid/Response.qll deleted file mode 100644 index 0512e7e7f4d..00000000000 --- a/python/ql/lib/semmle/python/web/pyramid/Response.qll +++ /dev/null @@ -1,37 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -import semmle.python.web.Http -private import semmle.python.web.pyramid.View - -/** - * A pyramid response, which is vulnerable to any sort of - * http response malice. - */ -deprecated class PyramidRoutedResponse extends HttpResponseTaintSink { - PyramidRoutedResponse() { - exists(PythonFunctionValue view | - is_pyramid_view_function(view.getScope()) and - this = view.getAReturnedNode() - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } - - override string toString() { result = "pyramid.routed.response" } -} - -deprecated class PyramidCookieSet extends CookieSet, CallNode { - PyramidCookieSet() { - exists(ControlFlowNode f | - f = this.getFunction().(AttrNode).getObject("set_cookie") and - f.pointsTo().getClass() = Value::named("pyramid.response.Response") - ) - } - - override string toString() { result = CallNode.super.toString() } - - override ControlFlowNode getKey() { result = this.getArg(0) } - - override ControlFlowNode getValue() { result = this.getArg(1) } -} diff --git a/python/ql/lib/semmle/python/web/pyramid/View.qll b/python/ql/lib/semmle/python/web/pyramid/View.qll deleted file mode 100644 index 37d9334cb07..00000000000 --- a/python/ql/lib/semmle/python/web/pyramid/View.qll +++ /dev/null @@ -1,9 +0,0 @@ -import python - -deprecated ModuleValue thePyramidViewModule() { result.getName() = "pyramid.view" } - -deprecated Value thePyramidViewConfig() { result = thePyramidViewModule().attr("view_config") } - -deprecated predicate is_pyramid_view_function(Function func) { - func.getADecorator().pointsTo().getClass() = thePyramidViewConfig() -} diff --git a/python/ql/lib/semmle/python/web/stdlib/Request.qll b/python/ql/lib/semmle/python/web/stdlib/Request.qll deleted file mode 100644 index ff850233616..00000000000 --- a/python/ql/lib/semmle/python/web/stdlib/Request.qll +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Provides the sources and taint-flow for HTTP servers defined using the standard library (stdlib). - * Specifically, we model `HttpRequestTaintSource`s from instances of `BaseHTTPRequestHandler` - * (or subclasses) and form parsing using `cgi.FieldStorage`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http - -/** Source of BaseHttpRequestHandler instances. */ -deprecated class StdLibRequestSource extends HttpRequestTaintSource { - StdLibRequestSource() { - exists(ClassValue cls | - cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler") - or - cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler") - | - this.(ControlFlowNode).pointsTo().getClass() = cls - ) - } - - override predicate isSourceOf(TaintKind kind) { kind instanceof BaseHTTPRequestHandlerKind } -} - -/** TaintKind for an instance of BaseHttpRequestHandler. */ -deprecated class BaseHTTPRequestHandlerKind extends TaintKind { - BaseHTTPRequestHandlerKind() { this = "BaseHTTPRequestHandlerKind" } - - override TaintKind getTaintOfAttribute(string name) { - name in ["requestline", "path"] and - result instanceof ExternalStringKind - or - name = "headers" and - result instanceof HTTPMessageKind - or - name = "rfile" and - result instanceof ExternalFileObject - } -} - -/** TaintKind for headers (instance of HttpMessage). */ -deprecated class HTTPMessageKind extends ExternalStringDictKind { - override TaintKind getTaintOfMethodResult(string name) { - result = super.getTaintOfMethodResult(name) - or - name = "get_all" and - result.(SequenceKind).getItem() = this.getValue() - or - name in ["as_bytes", "as_string"] and - result instanceof ExternalStringKind - } - - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - result = super.getTaintForFlowStep(fromnode, tonode) - or - exists(ClassValue cls | cls = ClassValue::unicode() or cls = ClassValue::bytes() | - tonode = cls.getACall() and - tonode.(CallNode).getArg(0) = fromnode and - result instanceof ExternalStringKind - ) - } -} - -/** Source of parsed HTTP forms (by using the `cgi` module). */ -deprecated class CgiFieldStorageSource extends HttpRequestTaintSource { - CgiFieldStorageSource() { this = Value::named("cgi.FieldStorage").getACall() } - - override predicate isSourceOf(TaintKind kind) { kind instanceof CgiFieldStorageFormKind } -} - -/** TaintKind for a parsed HTTP form. */ -deprecated class CgiFieldStorageFormKind extends TaintKind { - /* - * There is a slight difference between how we model form/fields and how it is handled by the code. - * In the code - * ``` - * form = cgi.FieldStorage() - * field = form['myfield'] - * ``` - * both `form` and `field` have the type `cgi.FieldStorage`. This allows the code to represent - * nested forms as `form['nested_form']['myfield']`. However, since HTML forms can't be nested - * we ignore that detail since it allows for a more clean modeling. - */ - - CgiFieldStorageFormKind() { this = "CgiFieldStorageFormKind" } - - override TaintKind getTaintOfAttribute(string name) { - name = "value" and result.(SequenceKind).getItem() instanceof CgiFieldStorageFieldKind - } - - override TaintKind getTaintOfMethodResult(string name) { - name = "getvalue" and - ( - result instanceof ExternalStringKind - or - result.(SequenceKind).getItem() instanceof ExternalStringKind - ) - or - name = "getfirst" and - result instanceof ExternalStringKind - or - name = "getlist" and - result.(SequenceKind).getItem() instanceof ExternalStringKind - } - - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - tonode.(SubscriptNode).getObject() = fromnode and - ( - result instanceof CgiFieldStorageFieldKind - or - result.(SequenceKind).getItem() instanceof CgiFieldStorageFieldKind - ) - } -} - -/** TaintKind for the field of a parsed HTTP form. */ -deprecated class CgiFieldStorageFieldKind extends TaintKind { - CgiFieldStorageFieldKind() { this = "CgiFieldStorageFieldKind" } - - override TaintKind getTaintOfAttribute(string name) { - name in ["filename", "value"] and result instanceof ExternalStringKind - or - name = "file" and result instanceof ExternalFileObject - } -} diff --git a/python/ql/lib/semmle/python/web/stdlib/Response.qll b/python/ql/lib/semmle/python/web/stdlib/Response.qll deleted file mode 100644 index 651201e204d..00000000000 --- a/python/ql/lib/semmle/python/web/stdlib/Response.qll +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Provides the sinks for HTTP servers defined with standard library (stdlib). - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http - -deprecated private predicate is_wfile(AttrNode wfile) { - exists(ClassValue cls | - // Python 2 - cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler") - or - // Python 3 - cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler") - | - wfile.getObject("wfile").pointsTo().getClass() = cls - ) -} - -/** Sink for `h.wfile.write` where `h` is an instance of BaseHttpRequestHandler. */ -deprecated class StdLibWFileWriteSink extends HttpResponseTaintSink { - StdLibWFileWriteSink() { - exists(CallNode call | - is_wfile(call.getFunction().(AttrNode).getObject("write")) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -/** Sink for `h.wfile.writelines` where `h` is an instance of BaseHttpRequestHandler. */ -deprecated class StdLibWFileWritelinesSink extends HttpResponseTaintSink { - StdLibWFileWritelinesSink() { - exists(CallNode call | - is_wfile(call.getFunction().(AttrNode).getObject("writelines")) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringSequenceKind } -} diff --git a/python/ql/lib/semmle/python/web/tornado/Redirect.qll b/python/ql/lib/semmle/python/web/tornado/Redirect.qll deleted file mode 100644 index 87965a9be23..00000000000 --- a/python/ql/lib/semmle/python/web/tornado/Redirect.qll +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Provides class representing the `tornado.redirect` function. - * This module is intended to be imported into a taint-tracking query - * to extend `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -import semmle.python.web.Http -import Tornado - -/** - * Represents an argument to the `tornado.redirect` function. - */ -deprecated class TornadoHttpRequestHandlerRedirect extends HttpRedirectTaintSink { - override string toString() { result = "tornado.HttpRequestHandler.redirect" } - - TornadoHttpRequestHandlerRedirect() { - exists(CallNode call, ControlFlowNode node | - node = call.getFunction().(AttrNode).getObject("redirect") and - isTornadoRequestHandlerInstance(node) and - this = call.getArg(0) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } -} diff --git a/python/ql/lib/semmle/python/web/tornado/Request.qll b/python/ql/lib/semmle/python/web/tornado/Request.qll deleted file mode 100644 index 77a02c230ae..00000000000 --- a/python/ql/lib/semmle/python/web/tornado/Request.qll +++ /dev/null @@ -1,69 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http -import Tornado - -/** A tornado.request.HttpRequest object */ -deprecated class TornadoRequest extends TaintKind { - TornadoRequest() { this = "tornado.request.HttpRequest" } - - override TaintKind getTaintOfAttribute(string name) { - result instanceof ExternalStringDictKind and - ( - name = "headers" or - name = "cookies" - ) - or - result instanceof ExternalStringKind and - ( - name = "uri" or - name = "query" or - name = "body" - ) - or - result instanceof ExternalStringSequenceDictKind and - ( - name = "arguments" or - name = "query_arguments" or - name = "body_arguments" - ) - } -} - -deprecated class TornadoRequestSource extends HttpRequestTaintSource { - TornadoRequestSource() { isTornadoRequestHandlerInstance(this.(AttrNode).getObject("request")) } - - override string toString() { result = "Tornado request source" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoRequest } -} - -deprecated class TornadoExternalInputSource extends HttpRequestTaintSource { - TornadoExternalInputSource() { - exists(string name | - name in ["get_argument", "get_query_argument", "get_body_argument", "decode_argument"] - | - this = callToNamedTornadoRequestHandlerMethod(name) - ) - } - - override string toString() { result = "Tornado request method" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } -} - -deprecated class TornadoExternalInputListSource extends HttpRequestTaintSource { - TornadoExternalInputListSource() { - exists(string name | - name = "get_arguments" or - name = "get_query_arguments" or - name = "get_body_arguments" - | - this = callToNamedTornadoRequestHandlerMethod(name) - ) - } - - override string toString() { result = "Tornado request method" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } -} diff --git a/python/ql/lib/semmle/python/web/tornado/Response.qll b/python/ql/lib/semmle/python/web/tornado/Response.qll deleted file mode 100644 index fed57b14a02..00000000000 --- a/python/ql/lib/semmle/python/web/tornado/Response.qll +++ /dev/null @@ -1,47 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -private import semmle.python.web.Http -import Tornado - -deprecated class TornadoConnection extends TaintKind { - TornadoConnection() { this = "tornado.http.connection" } -} - -deprecated class TornadoConnectionSource extends TaintSource { - TornadoConnectionSource() { - isTornadoRequestHandlerInstance(this.(AttrNode).getObject("connection")) - } - - override string toString() { result = "Tornado http connection source" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoConnection } -} - -deprecated class TornadoConnectionWrite extends HttpResponseTaintSink { - override string toString() { result = "tornado.connection.write" } - - TornadoConnectionWrite() { - exists(CallNode call, ControlFlowNode conn | - conn = call.getFunction().(AttrNode).getObject("write") and - this = call.getAnArg() and - exists(TornadoConnection tc | tc.taints(conn)) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } -} - -deprecated class TornadoHttpRequestHandlerWrite extends HttpResponseTaintSink { - override string toString() { result = "tornado.HttpRequestHandler.write" } - - TornadoHttpRequestHandlerWrite() { - exists(CallNode call, ControlFlowNode node | - node = call.getFunction().(AttrNode).getObject("write") and - this = call.getAnArg() and - isTornadoRequestHandlerInstance(node) - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } -} diff --git a/python/ql/lib/semmle/python/web/tornado/Tornado.qll b/python/ql/lib/semmle/python/web/tornado/Tornado.qll deleted file mode 100644 index 798ecff43ff..00000000000 --- a/python/ql/lib/semmle/python/web/tornado/Tornado.qll +++ /dev/null @@ -1,50 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http - -deprecated private ClassValue theTornadoRequestHandlerClass() { - result = Value::named("tornado.web.RequestHandler") -} - -deprecated ClassValue aTornadoRequestHandlerClass() { - result.getABaseType+() = theTornadoRequestHandlerClass() -} - -/** - * Holds if `node` is likely to refer to an instance of a tornado - * `RequestHandler` class. - */ -deprecated predicate isTornadoRequestHandlerInstance(ControlFlowNode node) { - node.pointsTo().getClass() = aTornadoRequestHandlerClass() - or - /* - * In some cases, the points-to analysis won't capture all instances we care - * about. For these, we use the following syntactic check. First, that - * `node` appears inside a method of a subclass of - * `tornado.web.RequestHandler`: - */ - - node.getScope().getEnclosingScope() = aTornadoRequestHandlerClass().getScope() and - /* Secondly, that `node` refers to the `self` argument: */ - node.isLoad() and - node.(NameNode).isSelf() -} - -deprecated CallNode callToNamedTornadoRequestHandlerMethod(string name) { - isTornadoRequestHandlerInstance(result.getFunction().(AttrNode).getObject(name)) -} - -deprecated class TornadoCookieSet extends CookieSet, CallNode { - TornadoCookieSet() { - exists(ControlFlowNode f | - f = this.getFunction().(AttrNode).getObject("set_cookie") and - isTornadoRequestHandlerInstance(f) - ) - } - - override string toString() { result = CallNode.super.toString() } - - override ControlFlowNode getKey() { result = this.getArg(0) } - - override ControlFlowNode getValue() { result = this.getArg(1) } -} diff --git a/python/ql/lib/semmle/python/web/turbogears/Request.qll b/python/ql/lib/semmle/python/web/turbogears/Request.qll deleted file mode 100644 index 48e063d0f99..00000000000 --- a/python/ql/lib/semmle/python/web/turbogears/Request.qll +++ /dev/null @@ -1,26 +0,0 @@ -import python -import semmle.python.security.strings.External -import semmle.python.web.Http -import TurboGears - -deprecated private class ValidatedMethodParameter extends Parameter { - ValidatedMethodParameter() { - exists(string name, TurboGearsControllerMethod method | - method.getArgByName(name) = this and - method.getValidationDict().getItem(_).(KeyValuePair).getKey().(StrConst).getText() = name - ) - } -} - -deprecated class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource { - UnvalidatedControllerMethodParameter() { - exists(Parameter p | - any(TurboGearsControllerMethod m | not m.getName() = "onerror").getAnArg() = p and - not p instanceof ValidatedMethodParameter and - not p.isSelf() and - p.(Name).getAFlowNode() = this - ) - } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/lib/semmle/python/web/turbogears/Response.qll b/python/ql/lib/semmle/python/web/turbogears/Response.qll deleted file mode 100644 index 331de6bce48..00000000000 --- a/python/ql/lib/semmle/python/web/turbogears/Response.qll +++ /dev/null @@ -1,31 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Basic -import semmle.python.web.Http -import TurboGears - -deprecated class ControllerMethodReturnValue extends HttpResponseTaintSink { - override string toString() { result = "TurboGears ControllerMethodReturnValue" } - - ControllerMethodReturnValue() { - exists(TurboGearsControllerMethod m | - m.getAReturnValueFlowNode() = this and - not m.isTemplated() - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof StringKind } -} - -deprecated class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink { - override string toString() { result = "TurboGears ControllerMethodTemplatedReturnValue" } - - ControllerMethodTemplatedReturnValue() { - exists(TurboGearsControllerMethod m | - m.getAReturnValueFlowNode() = this and - m.isTemplated() - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringDictKind } -} diff --git a/python/ql/lib/semmle/python/web/turbogears/TurboGears.qll b/python/ql/lib/semmle/python/web/turbogears/TurboGears.qll deleted file mode 100644 index 87006afe03a..00000000000 --- a/python/ql/lib/semmle/python/web/turbogears/TurboGears.qll +++ /dev/null @@ -1,37 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking - -deprecated private ClassValue theTurboGearsControllerClass() { - result = Value::named("tg.TGController") -} - -deprecated ClassValue aTurboGearsControllerClass() { - result.getABaseType+() = theTurboGearsControllerClass() -} - -deprecated class TurboGearsControllerMethod extends Function { - ControlFlowNode decorator; - - TurboGearsControllerMethod() { - aTurboGearsControllerClass().getScope() = this.getScope() and - decorator = this.getADecorator().getAFlowNode() and - /* Is decorated with @expose() or @expose(path) */ - ( - decorator.(CallNode).getFunction().(NameNode).getId() = "expose" - or - decorator.pointsTo().getClass() = Value::named("tg.expose") - ) - } - - private ControlFlowNode templateName() { result = decorator.(CallNode).getArg(0) } - - predicate isTemplated() { exists(this.templateName()) } - - Dict getValidationDict() { - exists(Call call | - call = this.getADecorator() and - call.getFunc().(Name).getId() = "validate" and - call.getArg(0).pointsTo(_, result) - ) - } -} diff --git a/python/ql/lib/semmle/python/web/twisted/Request.qll b/python/ql/lib/semmle/python/web/twisted/Request.qll deleted file mode 100644 index d1bcf879f0f..00000000000 --- a/python/ql/lib/semmle/python/web/twisted/Request.qll +++ /dev/null @@ -1,30 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http -import Twisted - -/** A twisted.web.http.Request object */ -deprecated class TwistedRequest extends TaintKind { - TwistedRequest() { this = "twisted.request.http.Request" } - - override TaintKind getTaintOfAttribute(string name) { - result instanceof ExternalStringSequenceDictKind and - name = "args" - or - result instanceof ExternalStringKind and - name = "uri" - } - - override TaintKind getTaintOfMethodResult(string name) { - name in ["getHeader", "getCookie", "getUser", "getPassword"] and - result instanceof ExternalStringKind - } -} - -deprecated class TwistedRequestSource extends HttpRequestTaintSource { - TwistedRequestSource() { isTwistedRequestInstance(this) } - - override string toString() { result = "Twisted request source" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof TwistedRequest } -} diff --git a/python/ql/lib/semmle/python/web/twisted/Response.qll b/python/ql/lib/semmle/python/web/twisted/Response.qll deleted file mode 100644 index 65313ab5280..00000000000 --- a/python/ql/lib/semmle/python/web/twisted/Response.qll +++ /dev/null @@ -1,45 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http -import semmle.python.security.strings.Basic -import Twisted -import Request - -deprecated class TwistedResponse extends HttpResponseTaintSink { - TwistedResponse() { - exists(PythonFunctionValue func, string name | - isKnownRequestHandlerMethodName(name) and - name = func.getName() and - func = getTwistedRequestHandlerMethod(name) and - this = func.getAReturnedNode() - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "Twisted response" } -} - -/** - * A sink of taint in the form of a "setter" method on a twisted request - * object, which affects the properties of the subsequent response sent to this - * request. - */ -deprecated class TwistedRequestSetter extends HttpResponseTaintSink { - TwistedRequestSetter() { - exists(CallNode call, ControlFlowNode node, string name | - ( - name = "setHeader" or - name = "addCookie" or - name = "write" - ) and - any(TwistedRequest t).taints(node) and - node = call.getFunction().(AttrNode).getObject(name) and - this = call.getAnArg() - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "Twisted request setter" } -} diff --git a/python/ql/lib/semmle/python/web/twisted/Twisted.qll b/python/ql/lib/semmle/python/web/twisted/Twisted.qll deleted file mode 100644 index 54dd1d959e8..00000000000 --- a/python/ql/lib/semmle/python/web/twisted/Twisted.qll +++ /dev/null @@ -1,52 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking - -deprecated private ClassValue theTwistedHttpRequestClass() { - result = Value::named("twisted.web.http.Request") -} - -deprecated private ClassValue theTwistedHttpResourceClass() { - result = Value::named("twisted.web.resource.Resource") -} - -deprecated ClassValue aTwistedRequestHandlerClass() { - result.getABaseType+() = theTwistedHttpResourceClass() -} - -deprecated FunctionValue getTwistedRequestHandlerMethod(string name) { - result = aTwistedRequestHandlerClass().declaredAttribute(name) -} - -bindingset[name] -deprecated predicate isKnownRequestHandlerMethodName(string name) { - name = "render" or - name.matches("render_%") -} - -/** - * Holds if `node` is likely to refer to an instance of the twisted - * `Request` class. - */ -deprecated predicate isTwistedRequestInstance(NameNode node) { - node.pointsTo().getClass() = theTwistedHttpRequestClass() - or - /* - * In points-to analysis cannot infer that a given object is an instance of - * the `twisted.web.http.Request` class, we also include any parameter - * called `request` that appears inside a subclass of a request handler - * class, and the appropriate arguments of known request handler methods. - */ - - exists(Function func | - func = node.getScope() and - func.getEnclosingScope() = aTwistedRequestHandlerClass().getScope() - | - /* Any parameter called `request` */ - node.getId() = "request" and - node.isParameter() - or - /* Any request parameter of a known request handler method */ - isKnownRequestHandlerMethodName(func.getName()) and - node.getNode() = func.getArg(1) - ) -} diff --git a/python/ql/lib/semmle/python/web/webob/Request.qll b/python/ql/lib/semmle/python/web/webob/Request.qll deleted file mode 100644 index 3c085b1d02d..00000000000 --- a/python/ql/lib/semmle/python/web/webob/Request.qll +++ /dev/null @@ -1,38 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.Http - -abstract deprecated class BaseWebobRequest extends TaintKind { - bindingset[this] - BaseWebobRequest() { any() } - - override TaintKind getTaintOfAttribute(string name) { - result instanceof ExternalStringDictKind and - ( - name = "GET" or - name = "POST" or - name = "headers" - ) - or - result instanceof ExternalStringKind and - name = "body" - } - - override TaintKind getTaintOfMethodResult(string name) { - result = this and - ( - name = "copy" or - name = "copy_get" or - name = "copy_body" - ) - or - result instanceof ExternalStringKind and - name = "as_bytes" - } -} - -deprecated class WebobRequest extends BaseWebobRequest { - WebobRequest() { this = "webob.Request" } - - override ClassValue getType() { result = Value::named("webob.request.Request") } -} diff --git a/python/ql/src/experimental/Security/CWE-074/JinjaBad.py b/python/ql/src/experimental/Security/CWE-074/JinjaBad.py deleted file mode 100644 index aaac3ec819e..00000000000 --- a/python/ql/src/experimental/Security/CWE-074/JinjaBad.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.urls import path -from django.http import HttpResponse -from jinja2 import Template as Jinja2_Template -from jinja2 import Environment, DictLoader, escape - - -def a(request): - # Load the template - template = request.GET['template'] - t = Jinja2_Template(template) - name = request.GET['name'] - # Render the template with the context data - html = t.render(name=escape(name)) - return HttpResponse(html) - - -urlpatterns = [ - path('a', a), -] diff --git a/python/ql/src/experimental/Security/CWE-074/JinjaGood.py b/python/ql/src/experimental/Security/CWE-074/JinjaGood.py deleted file mode 100644 index a1b60561850..00000000000 --- a/python/ql/src/experimental/Security/CWE-074/JinjaGood.py +++ /dev/null @@ -1,20 +0,0 @@ -from django.urls import path -from django.http import HttpResponse -from jinja2 import Template as Jinja2_Template -from jinja2 import Environment, DictLoader, escape - - -def a(request): - # Load the template - template = request.GET['template'] - env = SandboxedEnvironment(undefined=StrictUndefined) - t = env.from_string(template) - name = request.GET['name'] - # Render the template with the context data - html = t.render(name=escape(name)) - return HttpResponse(html) - - -urlpatterns = [ - path('a', a), -] diff --git a/python/ql/src/experimental/Security/CWE-074/TemplateInjection.qhelp b/python/ql/src/experimental/Security/CWE-074/TemplateInjection.qhelp deleted file mode 100644 index b044243fc8e..00000000000 --- a/python/ql/src/experimental/Security/CWE-074/TemplateInjection.qhelp +++ /dev/null @@ -1,24 +0,0 @@ - - - -

- Template Injection occurs when user input is embedded in a template in an unsafe manner. - When an attacker is able to use native template syntax to inject a malicious payload into a template, which is then executed server-side is results in Server Side Template Injection. -

-
- -

- To fix this, ensure that an untrusted value is not used as a template. If the application requirements do not alow this, use a sandboxed environment where access to unsafe attributes and methods is prohibited. -

-
- -

Consider the example given below, an untrusted HTTP parameter `template` is used to generate a Jinja2 template string. This can lead to remote code execution.

- - -

Here we have fixed the problem by using the Jinja sandbox environment for evaluating untrusted code.

- -
- -
  • Portswigger : [Server Side Template Injection](https://portswigger.net/web-security/server-side-template-injection)
  • -
    -
    diff --git a/python/ql/src/experimental/Security/CWE-074/TemplateInjection.ql b/python/ql/src/experimental/Security/CWE-074/TemplateInjection.ql deleted file mode 100644 index cbc3536ad7d..00000000000 --- a/python/ql/src/experimental/Security/CWE-074/TemplateInjection.ql +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @name Server Side Template Injection - * @description Using user-controlled data to create a template can cause security issues. - * @kind path-problem - * @problem.severity error - * @precision high - * @id py/template-injection - * @tags security - * experimental - * external/cwe/cwe-074 - */ - -import python -import semmle.python.security.Paths -/* Sources */ -import semmle.python.web.HttpRequest -/* Sinks */ -import experimental.semmle.python.templates.Ssti -/* Flow */ -import semmle.python.security.strings.Untrusted - -class TemplateInjectionConfiguration extends TaintTracking::Configuration { - TemplateInjectionConfiguration() { this = "Template injection configuration" } - - deprecated override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } - - deprecated override predicate isSink(TaintTracking::Sink sink) { sink instanceof SSTISink } -} - -from TemplateInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink -where config.hasFlowPath(src, sink) -select sink.getSink(), src, sink, "This Template depends on $@.", src.getSource(), - "a user-provided value" diff --git a/python/ql/src/experimental/Security/CWE-091/Xslt.qhelp b/python/ql/src/experimental/Security/CWE-091/Xslt.qhelp deleted file mode 100644 index 307314f00df..00000000000 --- a/python/ql/src/experimental/Security/CWE-091/Xslt.qhelp +++ /dev/null @@ -1,18 +0,0 @@ - - - -

    - Processing an unvalidated XSL stylesheet can allow an attacker to change the structure and contents of the resultant XML, include arbitrary files from the file system, or execute arbitrary code. -

    -
    - -

    - This vulnerability can be prevented by not allowing untrusted user input to be passed as an XSL stylesheet. - If the application logic necessitates processing untrusted XSL stylesheets, the input should be properly filtered and sanitized before use. -

    -
    - -

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

    - -
    -
    diff --git a/python/ql/src/experimental/Security/CWE-091/Xslt.ql b/python/ql/src/experimental/Security/CWE-091/Xslt.ql deleted file mode 100644 index 77f405f5f5a..00000000000 --- a/python/ql/src/experimental/Security/CWE-091/Xslt.ql +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @name XSLT query built from user-controlled sources - * @description Building a XSLT query from user-controlled sources is vulnerable to insertion of - * malicious XSLT code by the user. - * @kind path-problem - * @problem.severity error - * @precision high - * @id py/xslt-injection - * @tags security - * experimental - * external/cwe/cwe-643 - */ - -import python -import semmle.python.security.Paths -/* Sources */ -import semmle.python.web.HttpRequest -/* Sinks */ -import experimental.semmle.python.security.injection.XSLT - -class XsltInjectionConfiguration extends TaintTracking::Configuration { - XsltInjectionConfiguration() { this = "XSLT injection configuration" } - - deprecated override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } - - deprecated override predicate isSink(TaintTracking::Sink sink) { - sink instanceof XSLTInjection::XSLTInjectionSink - } -} - -from XsltInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink -where config.hasFlowPath(src, sink) -select sink.getSink(), src, sink, "This XSLT query depends on $@.", src.getSource(), - "a user-provided value" diff --git a/python/ql/src/experimental/Security/CWE-091/xslt.py b/python/ql/src/experimental/Security/CWE-091/xslt.py deleted file mode 100644 index 1655916c7e0..00000000000 --- a/python/ql/src/experimental/Security/CWE-091/xslt.py +++ /dev/null @@ -1,14 +0,0 @@ -from lxml import etree -from io import StringIO -from flask import Flask, request - -app = Flask(__name__) - - -@app.route("/xslt") -def bad(): - xsltQuery = request.args.get('xml', '') - xslt_root = etree.XML(xsltQuery) - f = StringIO('') - tree = etree.parse(f) - result_tree = tree.xslt(xslt_root) # Not OK diff --git a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll index 4d0057f8dc1..ff3f7189b18 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll @@ -8,7 +8,6 @@ import python import semmle.python.dataflow.TaintTracking -import semmle.python.web.HttpRequest /** Models XSLT Injection related classes and functions */ module XsltInjection { @@ -21,21 +20,6 @@ module XsltInjection { /** DEPRECATED: Alias for XsltInjectionSink */ deprecated class XSLTInjectionSink = XsltInjectionSink; - /** - * A kind of "taint", representing an untrusted XML string - */ - deprecated private class ExternalXmlStringKind extends ExternalStringKind { - ExternalXmlStringKind() { this = "etree.XML string" } - - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - etreeXml(fromnode, tonode) and result instanceof ExternalXmlKind - or - etreeFromStringList(fromnode, tonode) and result instanceof ExternalXmlKind - or - etreeFromString(fromnode, tonode) and result instanceof ExternalXmlKind - } - } - /** * A kind of "taint", representing a XML encoded string */ @@ -43,32 +27,6 @@ module XsltInjection { ExternalXmlKind() { this = "lxml etree xml" } } - private predicate etreeXml(ControlFlowNode fromnode, CallNode tonode) { - // etree.XML("") - exists(CallNode call | call.getFunction().(AttrNode).getObject("XML").pointsTo(etree()) | - call.getArg(0) = fromnode and - call = tonode - ) - } - - private predicate etreeFromString(ControlFlowNode fromnode, CallNode tonode) { - // etree.fromstring(text, parser=None) - exists(CallNode call | call.getFunction().(AttrNode).getObject("fromstring").pointsTo(etree()) | - call.getArg(0) = fromnode and - call = tonode - ) - } - - private predicate etreeFromStringList(ControlFlowNode fromnode, CallNode tonode) { - // etree.fromstringlist(strings, parser=None) - exists(CallNode call | - call.getFunction().(AttrNode).getObject("fromstringlist").pointsTo(etree()) - | - call.getArg(0) = fromnode and - call = tonode - ) - } - /** * A Sink representing an argument to the `etree.XSLT` call. * diff --git a/python/ql/src/experimental/semmle/python/templates/Airspeed.qll b/python/ql/src/experimental/semmle/python/templates/Airspeed.qll deleted file mode 100644 index dc266ac0f82..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/Airspeed.qll +++ /dev/null @@ -1,27 +0,0 @@ -/** Provides classes which model the `airspeed` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -/** returns the ClassValue representing `airspeed.Template` */ -deprecated ClassValue theAirspeedTemplateClass() { result = Value::named("airspeed.Template") } - -/** - * A sink representing the `airspeed.Template` class instantiation argument. - * - * import airspeed - * temp = airspeed.Template(`"sink"`) - */ -deprecated class AirspeedTemplateSink extends SSTISink { - override string toString() { result = "argument to airspeed.Template()" } - - AirspeedTemplateSink() { - exists(CallNode call | - call.getFunction().pointsTo(theAirspeedTemplateClass()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/src/experimental/semmle/python/templates/Bottle.qll b/python/ql/src/experimental/semmle/python/templates/Bottle.qll deleted file mode 100644 index 1f5bd2bba85..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/Bottle.qll +++ /dev/null @@ -1,48 +0,0 @@ -/** Provides classes which model the `bottle` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -/** returns the ClassValue representing `bottle.SimpleTemplate` */ -deprecated ClassValue theBottleSimpleTemplateClass() { - result = Value::named("bottle.SimpleTemplate") -} - -/** - * A sink representing the `bottle.SimpleTemplate` class instantiation argument. - * - * from bottle import SimpleTemplate - * template = SimpleTemplate(`sink`) - */ -deprecated class BottleSimpleTemplateSink extends SSTISink { - override string toString() { result = "argument to bottle.SimpleTemplate()" } - - BottleSimpleTemplateSink() { - exists(CallNode call | - call.getFunction().pointsTo(theBottleSimpleTemplateClass()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -/** - * A sink representing the `bottle.template` function call argument. - * - * from bottle import template - * tmp = template(`sink`) - */ -deprecated class BottleTemplateSink extends SSTISink { - override string toString() { result = "argument to bottle.template()" } - - BottleTemplateSink() { - exists(CallNode call | - call.getFunction() = theBottleModule().attr("template").getAReference() and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/src/experimental/semmle/python/templates/Chameleon.qll b/python/ql/src/experimental/semmle/python/templates/Chameleon.qll deleted file mode 100644 index f094dda97b5..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/Chameleon.qll +++ /dev/null @@ -1,29 +0,0 @@ -/** Provides classes which model the `Chameleon` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -/** returns the ClassValue representing `chameleon.PageTemplate` */ -deprecated ClassValue theChameleonPageTemplateClass() { - result = Value::named("chameleon.PageTemplate") -} - -/** - * A sink representing the `chameleon.PageTemplate` class instantiation argument. - * - * from chameleon import PageTemplate - * template = PageTemplate(`sink`) - */ -deprecated class ChameleonTemplateSink extends SSTISink { - override string toString() { result = "argument to Chameleon.PageTemplate()" } - - ChameleonTemplateSink() { - exists(CallNode call | - call.getFunction().pointsTo(theChameleonPageTemplateClass()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/src/experimental/semmle/python/templates/Cheetah.qll b/python/ql/src/experimental/semmle/python/templates/Cheetah.qll deleted file mode 100644 index 9812fdb7c88..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/Cheetah.qll +++ /dev/null @@ -1,39 +0,0 @@ -/** Provides classes which model the `Cheetah3` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -/** returns the ClassValue representing `Cheetah.Template.Template` */ -deprecated ClassValue theCheetahTemplateClass() { - result = Value::named("Cheetah.Template.Template") -} - -/** - * A sink representing the instantiation argument of any class which derives from - * the `Cheetah.Template.Template` class . - * - * from Cheetah.Template import Template - * class Template3(Template): - * title = 'Hello World Example!' - * contents = 'Hello World!' - * t3 = Template3("sink") - * - * This will also detect cases of the following type : - * - * from Cheetah.Template import Template - * t3 = Template("sink") - */ -deprecated class CheetahTemplateInstantiationSink extends SSTISink { - override string toString() { result = "argument to Cheetah.Template.Template()" } - - CheetahTemplateInstantiationSink() { - exists(CallNode call, ClassValue cv | - cv.getASuperType() = theCheetahTemplateClass() and - call.getFunction().pointsTo(cv) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/src/experimental/semmle/python/templates/Chevron.qll b/python/ql/src/experimental/semmle/python/templates/Chevron.qll deleted file mode 100644 index cc93016891c..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/Chevron.qll +++ /dev/null @@ -1,36 +0,0 @@ -/** Provides classes which model the `chevron` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -/** returns the Value representing `chevron.render` function */ -deprecated Value theChevronRenderFunc() { result = Value::named("chevron.render") } - -/** - * A sink representing the `chevron.render` function call argument. - * - * import chevron - * tmp = chevron.render(`sink`,{ 'key' : 'value' }) - */ -deprecated class ChevronRenderSink extends SSTISink { - override string toString() { result = "argument to chevron.render()" } - - ChevronRenderSink() { - exists(CallNode call | - call.getFunction() = theChevronRenderFunc().getAReference() and - call.getArg(0) = this - ) - // TODO: this should also detect : - // import chevron - // args = { - // 'template': 'sink', - // 'data': { - // 'mustache': 'World' - // } - // } - // chevron.render(**args) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll b/python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll deleted file mode 100644 index 1089ab872ec..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll +++ /dev/null @@ -1,35 +0,0 @@ -/** Provides classes which model the `DjangoTemplate` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -deprecated ClassValue theDjangoTemplateClass() { result = Value::named("django.template.Template") } - -/** - * A sink representing `django.template.Template` class instantiation argument. - * - * from django.template import Template - * template = Template(`sink`) - */ -deprecated class DjangoTemplateTemplateSink extends SSTISink { - override string toString() { result = "argument to Django.template()" } - - DjangoTemplateTemplateSink() { - exists(CallNode call | - call.getFunction().pointsTo(theDjangoTemplateClass()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} -// TODO (intentionally commented out QLDoc, since qlformat will delete those lines otherwise) -// /** -// * Sinks representing the django.template.Template class instantiation. -// * -// * from django.template import engines -// * -// * django_engine = engines["django"] -// * template = django_engine.from_string(`sink`) -// */ diff --git a/python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll b/python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll deleted file mode 100644 index c0f3c90235d..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll +++ /dev/null @@ -1,28 +0,0 @@ -/** Provides classes which model templates in the`flask` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -deprecated Value theFlaskRenderTemplateClass() { - result = Value::named("flask.render_template_string") -} - -/** - * A sink representing `flask.render_template_string` function call argument. - * - * from flask import render_template_string - * render_template_string(`sink`) - */ -deprecated class FlaskTemplateSink extends SSTISink { - override string toString() { result = "argument to flask.render_template_string()" } - - FlaskTemplateSink() { - exists(CallNode call | - call.getFunction().pointsTo(theFlaskRenderTemplateClass()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/src/experimental/semmle/python/templates/Genshi.qll b/python/ql/src/experimental/semmle/python/templates/Genshi.qll deleted file mode 100644 index c808d7c60f8..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/Genshi.qll +++ /dev/null @@ -1,53 +0,0 @@ -/** Provides classes which model the `Genshi` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -/** returns the ClassValue representing `Genshi.template.TextTemplate` */ -deprecated ClassValue theGenshiTextTemplateClass() { - result = Value::named("genshi.template.TextTemplate") -} - -/** returns the ClassValue representing `Genshi.template.MarkupTemplate` */ -deprecated ClassValue theGenshiMarkupTemplateClass() { - result = Value::named("genshi.template.MarkupTemplate") -} - -/** - * A sink representing the `genshi.template.TextTemplate` class instantiation argument. - * - * from genshi.template import TextTemplate - * tmpl = TextTemplate('sink') - */ -deprecated class GenshiTextTemplateSink extends SSTISink { - override string toString() { result = "argument to genshi.template.TextTemplate()" } - - GenshiTextTemplateSink() { - exists(CallNode call | - call.getFunction().pointsTo(theGenshiTextTemplateClass()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -/** - * A sink representing the `genshi.template.MarkupTemplate` class instantiation argument. - * - * from genshi.template import MarkupTemplate - * tmpl = MarkupTemplate('sink') - */ -deprecated class GenshiMarkupTemplateSink extends SSTISink { - override string toString() { result = "argument to genshi.template.MarkupTemplate()" } - - GenshiMarkupTemplateSink() { - exists(CallNode call | - call.getFunction().pointsTo(theGenshiMarkupTemplateClass()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/src/experimental/semmle/python/templates/Jinja.qll b/python/ql/src/experimental/semmle/python/templates/Jinja.qll deleted file mode 100644 index 44bc103cf04..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/Jinja.qll +++ /dev/null @@ -1,49 +0,0 @@ -/** Provides classes which model the `Jinja2` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -/** returns the ClassValue representing `jinja2.Template` */ -deprecated ClassValue theJinja2TemplateClass() { result = Value::named("jinja2.Template") } - -/** returns the ClassValue representing `jinja2.Template` */ -deprecated Value theJinja2FromStringValue() { result = Value::named("jinja2.from_string") } - -/** - * A sink representing the `jinja2.Template` class instantiation argument. - * - * from jinja2 import Template - * template = Template(`sink`) - */ -deprecated class Jinja2TemplateSink extends SSTISink { - override string toString() { result = "argument to jinja2.Template()" } - - Jinja2TemplateSink() { - exists(CallNode call | - call.getFunction().pointsTo(theJinja2TemplateClass()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} - -/** - * A sink representing the `jinja2.from_string` function call argument. - * - * from jinja2 import from_string - * template = from_string(`sink`) - */ -deprecated class Jinja2FromStringSink extends SSTISink { - override string toString() { result = "argument to jinja2.from_string()" } - - Jinja2FromStringSink() { - exists(CallNode call | - call.getFunction().pointsTo(theJinja2FromStringValue()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/src/experimental/semmle/python/templates/Mako.qll b/python/ql/src/experimental/semmle/python/templates/Mako.qll deleted file mode 100644 index b8634b3001a..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/Mako.qll +++ /dev/null @@ -1,27 +0,0 @@ -/** Provides classes which model the `Mako` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -/** returns the ClassValue representing `mako.template.Template` */ -deprecated ClassValue theMakoTemplateClass() { result = Value::named("mako.template.Template") } - -/** - * A sink representing the `mako.template.Template` class instantiation argument. - * - * from mako.template import Template - * mytemplate = Template("hello world!") - */ -deprecated class MakoTemplateSink extends SSTISink { - override string toString() { result = "argument to mako.template.Template()" } - - MakoTemplateSink() { - exists(CallNode call | - call.getFunction().pointsTo(theMakoTemplateClass()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/src/experimental/semmle/python/templates/SSTISink.qll b/python/ql/src/experimental/semmle/python/templates/SSTISink.qll deleted file mode 100644 index 1a68fe17b68..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/SSTISink.qll +++ /dev/null @@ -1,7 +0,0 @@ -import semmle.python.dataflow.TaintTracking - -/** - * A generic taint sink that is vulnerable to template inclusions. - * The `temp` in `jinja2.Template(temp)` and similar. - */ -abstract deprecated class SSTISink extends TaintSink { } diff --git a/python/ql/src/experimental/semmle/python/templates/Ssti.qll b/python/ql/src/experimental/semmle/python/templates/Ssti.qll deleted file mode 100644 index eb4f8d0ec2f..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/Ssti.qll +++ /dev/null @@ -1,13 +0,0 @@ -/** Imports all files which model potential SSTI sinks */ - -import experimental.semmle.python.templates.Airspeed -import experimental.semmle.python.templates.Bottle -import experimental.semmle.python.templates.Chameleon -import experimental.semmle.python.templates.Cheetah -import experimental.semmle.python.templates.Chevron -import experimental.semmle.python.templates.DjangoTemplate -import experimental.semmle.python.templates.FlaskTemplate -import experimental.semmle.python.templates.Genshi -import experimental.semmle.python.templates.Jinja -import experimental.semmle.python.templates.Mako -import experimental.semmle.python.templates.TRender diff --git a/python/ql/src/experimental/semmle/python/templates/TRender.qll b/python/ql/src/experimental/semmle/python/templates/TRender.qll deleted file mode 100644 index 8d5431ad9e0..00000000000 --- a/python/ql/src/experimental/semmle/python/templates/TRender.qll +++ /dev/null @@ -1,27 +0,0 @@ -/** Provides classes which model the `TRender` package. */ - -import python -import semmle.python.web.HttpRequest -import experimental.semmle.python.templates.SSTISink - -/** returns the ClassValue representing `trender.TRender` */ -deprecated ClassValue theTRenderTemplateClass() { result = Value::named("trender.TRender") } - -/** - * A sink representing the `trender.TRender` class instantiation argument. - * - * from trender import TRender - * template = TRender(`sink`) - */ -deprecated class TRenderTemplateSink extends SSTISink { - override string toString() { result = "argument to trender.TRender()" } - - TRenderTemplateSink() { - exists(CallNode call | - call.getFunction().pointsTo(theTRenderTemplateClass()) and - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } -} diff --git a/python/ql/test/3/library-tests/taint/strings/Taint.qll b/python/ql/test/3/library-tests/taint/strings/Taint.qll deleted file mode 100644 index 3368a1c4f70..00000000000 --- a/python/ql/test/3/library-tests/taint/strings/Taint.qll +++ /dev/null @@ -1,44 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted -import semmle.python.security.Exceptions - -class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "taint source" } -} - -class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - - override string toString() { result = "list taint source" } -} - -class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - - override string toString() { result = "dict taint source" } -} - -class ExceptionInfoSource extends TaintSource { - ExceptionInfoSource() { this.(NameNode).getId() = "TAINTED_EXCEPTION_INFO" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfo } - - override string toString() { result = "Exception info source" } -} - -class ExternalFileObjectSource extends TaintSource { - ExternalFileObjectSource() { this.(NameNode).getId() = "TAINTED_FILE" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalFileObject } - - override string toString() { result = "Tainted file source" } -} diff --git a/python/ql/test/3/library-tests/taint/strings/TestTaint.expected b/python/ql/test/3/library-tests/taint/strings/TestTaint.expected deleted file mode 100644 index 3e5e988f825..00000000000 --- a/python/ql/test/3/library-tests/taint/strings/TestTaint.expected +++ /dev/null @@ -1 +0,0 @@ -| test.py:4 | ok | fstring | Fstring | externally controlled string | diff --git a/python/ql/test/3/library-tests/taint/strings/TestTaint.ql b/python/ql/test/3/library-tests/taint/strings/TestTaint.ql deleted file mode 100644 index 7b9c6025c9d..00000000000 --- a/python/ql/test/3/library-tests/taint/strings/TestTaint.ql +++ /dev/null @@ -1,33 +0,0 @@ -import python -import semmle.python.security.TaintTracking -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted -import Taint - -from - Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, - string taint_string -where - call.getLocation().getFile().getShortName() = "test.py" and - ( - call.getFunc().(Name).getId() = "ensure_tainted" and - expected_taint = true - or - call.getFunc().(Name).getId() = "ensure_not_tainted" and - expected_taint = false - ) and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "" and - has_taint = false - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) and - has_taint = true - ) and - if expected_taint = has_taint then test_res = "ok " else test_res = "fail" -// if expected_taint = has_taint then test_res = "✓" else test_res = "✕" -select arg.getLocation().toString(), test_res, call.getScope().(Function).getName(), arg.toString(), - taint_string diff --git a/python/ql/test/3/library-tests/taint/strings/test.py b/python/ql/test/3/library-tests/taint/strings/test.py deleted file mode 100644 index e1c25b5dccc..00000000000 --- a/python/ql/test/3/library-tests/taint/strings/test.py +++ /dev/null @@ -1,5 +0,0 @@ -def fstring(): - tainted_string = TAINTED_STRING - ensure_tainted( - f"foo {tainted_string} bar" - ) diff --git a/python/ql/test/3/library-tests/taint/unpacking/Taint.qll b/python/ql/test/3/library-tests/taint/unpacking/Taint.qll deleted file mode 100644 index 010b9738c5c..00000000000 --- a/python/ql/test/3/library-tests/taint/unpacking/Taint.qll +++ /dev/null @@ -1,27 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted - -class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "taint source" } -} - -class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - - override string toString() { result = "list taint source" } -} - -class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - - override string toString() { result = "dict taint source" } -} diff --git a/python/ql/test/3/library-tests/taint/unpacking/TestTaint.expected b/python/ql/test/3/library-tests/taint/unpacking/TestTaint.expected deleted file mode 100644 index b6aacc7d670..00000000000 --- a/python/ql/test/3/library-tests/taint/unpacking/TestTaint.expected +++ /dev/null @@ -1,9 +0,0 @@ -| test.py:11 | extended_unpacking | first | externally controlled string | -| test.py:11 | extended_unpacking | last | externally controlled string | -| test.py:11 | extended_unpacking | rest | [externally controlled string] | -| test.py:16 | also_allowed | a | [externally controlled string] | -| test.py:24 | also_allowed | b | NO TAINT | -| test.py:24 | also_allowed | c | NO TAINT | -| test.py:31 | nested | x | externally controlled string | -| test.py:31 | nested | xs | [externally controlled string] | -| test.py:31 | nested | ys | [externally controlled string] | diff --git a/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql b/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql deleted file mode 100644 index 47883578516..00000000000 --- a/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql +++ /dev/null @@ -1,19 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import Taint - -from Call call, Expr arg, string taint_string -where - call.getLocation().getFile().getShortName() = "test.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) - ) -select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string diff --git a/python/ql/test/3/library-tests/taint/unpacking/test.py b/python/ql/test/3/library-tests/taint/unpacking/test.py deleted file mode 100644 index 6807ddebee8..00000000000 --- a/python/ql/test/3/library-tests/taint/unpacking/test.py +++ /dev/null @@ -1,31 +0,0 @@ -# Extended Iterable Unpacking -- PEP 3132 -# https://www.python.org/dev/peps/pep-3132/ - - -def test(*args): - pass - - -def extended_unpacking(): - first, *rest, last = TAINTED_LIST - test(first, rest, last) - - -def also_allowed(): - *a, = TAINTED_LIST - test(a) - - # for b, *c in [(1, 2, 3), (4, 5, 6, 7)]: - # print(c) - # i=0; c=[2,3] - # i=1; c=[5,6,7] - - for b, *c in [TAINTED_LIST, TAINTED_LIST]: - test(b, c) # TODO: mark `c` as [taint] - -def nested(): - l = TAINTED_LIST - ll = [l,l] - - [[x, *xs], ys] = ll - test(x, xs, ys) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.expected deleted file mode 100644 index 058a53bdf91..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.expected +++ /dev/null @@ -1,60 +0,0 @@ -edges -| AirspeedSsti.py:10:16:10:27 | dict of externally controlled string | AirspeedSsti.py:10:16:10:43 | externally controlled string | -| AirspeedSsti.py:10:16:10:27 | dict of externally controlled string | AirspeedSsti.py:10:16:10:43 | externally controlled string | -| AirspeedSsti.py:10:16:10:43 | externally controlled string | AirspeedSsti.py:11:30:11:37 | externally controlled string | -| AirspeedSsti.py:10:16:10:43 | externally controlled string | AirspeedSsti.py:11:30:11:37 | externally controlled string | -| ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:10:16:10:43 | externally controlled string | -| ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:10:16:10:43 | externally controlled string | -| ChevronSsti.py:10:16:10:43 | externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string | -| ChevronSsti.py:10:16:10:43 | externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string | -| DjangoTemplates.py:6:8:6:14 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest | -| DjangoTemplates.py:6:8:6:14 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest | -| DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict | -| DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict | -| DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict | DjangoTemplates.py:8:16:8:38 | externally controlled string | -| DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict | DjangoTemplates.py:8:16:8:38 | externally controlled string | -| DjangoTemplates.py:8:16:8:38 | externally controlled string | DjangoTemplates.py:9:18:9:25 | externally controlled string | -| DjangoTemplates.py:8:16:8:38 | externally controlled string | DjangoTemplates.py:9:18:9:25 | externally controlled string | -| FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string | -| FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string | -| JinjaSsti.py:7:7:7:13 | django.request.HttpRequest | JinjaSsti.py:9:16:9:22 | django.request.HttpRequest | -| JinjaSsti.py:7:7:7:13 | django.request.HttpRequest | JinjaSsti.py:9:16:9:22 | django.request.HttpRequest | -| JinjaSsti.py:9:16:9:22 | django.request.HttpRequest | JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict | -| JinjaSsti.py:9:16:9:22 | django.request.HttpRequest | JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict | -| JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict | JinjaSsti.py:9:16:9:38 | externally controlled string | -| JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict | JinjaSsti.py:9:16:9:38 | externally controlled string | -| JinjaSsti.py:9:16:9:38 | externally controlled string | JinjaSsti.py:10:25:10:32 | externally controlled string | -| JinjaSsti.py:9:16:9:38 | externally controlled string | JinjaSsti.py:10:25:10:32 | externally controlled string | -| JinjaSsti.py:16:7:16:13 | django.request.HttpRequest | JinjaSsti.py:19:16:19:22 | django.request.HttpRequest | -| JinjaSsti.py:16:7:16:13 | django.request.HttpRequest | JinjaSsti.py:19:16:19:22 | django.request.HttpRequest | -| JinjaSsti.py:19:16:19:22 | django.request.HttpRequest | JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict | -| JinjaSsti.py:19:16:19:22 | django.request.HttpRequest | JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict | -| JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict | JinjaSsti.py:19:16:19:38 | externally controlled string | -| JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict | JinjaSsti.py:19:16:19:38 | externally controlled string | -| JinjaSsti.py:19:16:19:38 | externally controlled string | JinjaSsti.py:20:28:20:35 | externally controlled string | -| JinjaSsti.py:19:16:19:38 | externally controlled string | JinjaSsti.py:20:28:20:35 | externally controlled string | -| MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:8:16:8:22 | django.request.HttpRequest | -| MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:8:16:8:22 | django.request.HttpRequest | -| MakoSsti.py:8:16:8:22 | django.request.HttpRequest | MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | -| MakoSsti.py:8:16:8:22 | django.request.HttpRequest | MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | -| MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | MakoSsti.py:8:16:8:38 | externally controlled string | -| MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | MakoSsti.py:8:16:8:38 | externally controlled string | -| MakoSsti.py:8:16:8:38 | externally controlled string | MakoSsti.py:9:27:9:34 | externally controlled string | -| MakoSsti.py:8:16:8:38 | externally controlled string | MakoSsti.py:9:27:9:34 | externally controlled string | -| TRender.py:5:13:5:19 | django.request.HttpRequest | TRender.py:6:16:6:22 | django.request.HttpRequest | -| TRender.py:5:13:5:19 | django.request.HttpRequest | TRender.py:6:16:6:22 | django.request.HttpRequest | -| TRender.py:6:16:6:22 | django.request.HttpRequest | TRender.py:6:16:6:26 | django.http.request.QueryDict | -| TRender.py:6:16:6:22 | django.request.HttpRequest | TRender.py:6:16:6:26 | django.http.request.QueryDict | -| TRender.py:6:16:6:26 | django.http.request.QueryDict | TRender.py:6:16:6:38 | externally controlled string | -| TRender.py:6:16:6:26 | django.http.request.QueryDict | TRender.py:6:16:6:38 | externally controlled string | -| TRender.py:6:16:6:38 | externally controlled string | TRender.py:7:24:7:31 | externally controlled string | -| TRender.py:6:16:6:38 | externally controlled string | TRender.py:7:24:7:31 | externally controlled string | -#select -| AirspeedSsti.py:11:30:11:37 | template | AirspeedSsti.py:10:16:10:27 | dict of externally controlled string | AirspeedSsti.py:11:30:11:37 | externally controlled string | This Template depends on $@. | AirspeedSsti.py:10:16:10:27 | Attribute | a user-provided value | -| ChevronSsti.py:11:27:11:34 | template | ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string | This Template depends on $@. | ChevronSsti.py:10:16:10:27 | Attribute | a user-provided value | -| DjangoTemplates.py:9:18:9:25 | template | DjangoTemplates.py:6:8:6:14 | django.request.HttpRequest | DjangoTemplates.py:9:18:9:25 | externally controlled string | This Template depends on $@. | DjangoTemplates.py:6:8:6:14 | request | a user-provided value | -| FlaskTemplate.py:17:41:17:68 | Attribute() | FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string | This Template depends on $@. | FlaskTemplate.py:17:41:17:52 | Attribute | a user-provided value | -| JinjaSsti.py:10:25:10:32 | template | JinjaSsti.py:7:7:7:13 | django.request.HttpRequest | JinjaSsti.py:10:25:10:32 | externally controlled string | This Template depends on $@. | JinjaSsti.py:7:7:7:13 | request | a user-provided value | -| JinjaSsti.py:20:28:20:35 | template | JinjaSsti.py:16:7:16:13 | django.request.HttpRequest | JinjaSsti.py:20:28:20:35 | externally controlled string | This Template depends on $@. | JinjaSsti.py:16:7:16:13 | request | a user-provided value | -| MakoSsti.py:9:27:9:34 | template | MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:9:27:9:34 | externally controlled string | This Template depends on $@. | MakoSsti.py:6:10:6:16 | request | a user-provided value | -| TRender.py:7:24:7:31 | template | TRender.py:5:13:5:19 | django.request.HttpRequest | TRender.py:7:24:7:31 | externally controlled string | This Template depends on $@. | TRender.py:5:13:5:19 | request | a user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.qlref b/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.qlref deleted file mode 100644 index 90efec9f636..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE-074/TemplateInjection.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.expected b/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.expected deleted file mode 100644 index 89f19160f69..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.expected +++ /dev/null @@ -1,47 +0,0 @@ -edges -| xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:10:17:10:43 | etree.XML string | -| xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:10:17:10:43 | etree.XML string | -| xslt.py:10:17:10:43 | etree.XML string | xslt.py:11:27:11:35 | etree.XML string | -| xslt.py:10:17:10:43 | etree.XML string | xslt.py:11:27:11:35 | etree.XML string | -| xslt.py:11:17:11:36 | lxml etree xml | xslt.py:14:29:14:37 | lxml etree xml | -| xslt.py:11:17:11:36 | lxml etree xml | xslt.py:14:29:14:37 | lxml etree xml | -| xslt.py:11:27:11:35 | etree.XML string | xslt.py:11:17:11:36 | lxml etree xml | -| xslt.py:11:27:11:35 | etree.XML string | xslt.py:11:17:11:36 | lxml etree xml | -| xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:10:17:10:43 | etree.XML string | -| xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:10:17:10:43 | etree.XML string | -| xsltInjection.py:10:17:10:43 | etree.XML string | xsltInjection.py:11:27:11:35 | etree.XML string | -| xsltInjection.py:10:17:10:43 | etree.XML string | xsltInjection.py:11:27:11:35 | etree.XML string | -| xsltInjection.py:11:17:11:36 | lxml etree xml | xsltInjection.py:12:28:12:36 | lxml etree xml | -| xsltInjection.py:11:17:11:36 | lxml etree xml | xsltInjection.py:12:28:12:36 | lxml etree xml | -| xsltInjection.py:11:27:11:35 | etree.XML string | xsltInjection.py:11:17:11:36 | lxml etree xml | -| xsltInjection.py:11:27:11:35 | etree.XML string | xsltInjection.py:11:17:11:36 | lxml etree xml | -| xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:17:17:17:43 | etree.XML string | -| xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:17:17:17:43 | etree.XML string | -| xsltInjection.py:17:17:17:43 | etree.XML string | xsltInjection.py:18:27:18:35 | etree.XML string | -| xsltInjection.py:17:17:17:43 | etree.XML string | xsltInjection.py:18:27:18:35 | etree.XML string | -| xsltInjection.py:18:17:18:36 | lxml etree xml | xsltInjection.py:21:29:21:37 | lxml etree xml | -| xsltInjection.py:18:17:18:36 | lxml etree xml | xsltInjection.py:21:29:21:37 | lxml etree xml | -| xsltInjection.py:18:27:18:35 | etree.XML string | xsltInjection.py:18:17:18:36 | lxml etree xml | -| xsltInjection.py:18:27:18:35 | etree.XML string | xsltInjection.py:18:17:18:36 | lxml etree xml | -| xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:26:17:26:43 | etree.XML string | -| xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:26:17:26:43 | etree.XML string | -| xsltInjection.py:26:17:26:43 | etree.XML string | xsltInjection.py:27:27:27:35 | etree.XML string | -| xsltInjection.py:26:17:26:43 | etree.XML string | xsltInjection.py:27:27:27:35 | etree.XML string | -| xsltInjection.py:27:17:27:36 | lxml etree xml | xsltInjection.py:31:24:31:32 | lxml etree xml | -| xsltInjection.py:27:17:27:36 | lxml etree xml | xsltInjection.py:31:24:31:32 | lxml etree xml | -| xsltInjection.py:27:27:27:35 | etree.XML string | xsltInjection.py:27:17:27:36 | lxml etree xml | -| xsltInjection.py:27:27:27:35 | etree.XML string | xsltInjection.py:27:17:27:36 | lxml etree xml | -| xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:35:17:35:43 | etree.XML string | -| xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:35:17:35:43 | etree.XML string | -| xsltInjection.py:35:17:35:43 | etree.XML string | xsltInjection.py:36:34:36:42 | etree.XML string | -| xsltInjection.py:35:17:35:43 | etree.XML string | xsltInjection.py:36:34:36:42 | etree.XML string | -| xsltInjection.py:36:17:36:43 | lxml etree xml | xsltInjection.py:40:24:40:32 | lxml etree xml | -| xsltInjection.py:36:17:36:43 | lxml etree xml | xsltInjection.py:40:24:40:32 | lxml etree xml | -| xsltInjection.py:36:34:36:42 | etree.XML string | xsltInjection.py:36:17:36:43 | lxml etree xml | -| xsltInjection.py:36:34:36:42 | etree.XML string | xsltInjection.py:36:17:36:43 | lxml etree xml | -#select -| xslt.py:14:29:14:37 | xslt_root | xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:14:29:14:37 | lxml etree xml | This XSLT query depends on $@. | xslt.py:10:17:10:28 | Attribute | a user-provided value | -| xsltInjection.py:12:28:12:36 | xslt_root | xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:12:28:12:36 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:10:17:10:28 | Attribute | a user-provided value | -| xsltInjection.py:21:29:21:37 | xslt_root | xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:21:29:21:37 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:17:17:17:28 | Attribute | a user-provided value | -| xsltInjection.py:31:24:31:32 | xslt_root | xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:31:24:31:32 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:26:17:26:28 | Attribute | a user-provided value | -| xsltInjection.py:40:24:40:32 | xslt_root | xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:40:24:40:32 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:35:17:35:28 | Attribute | a user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.qlref b/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.qlref deleted file mode 100644 index 988d13e98a6..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE-091/Xslt.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091/xslt.py b/python/ql/test/experimental/query-tests/Security/CWE-091/xslt.py deleted file mode 100644 index 1655916c7e0..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-091/xslt.py +++ /dev/null @@ -1,14 +0,0 @@ -from lxml import etree -from io import StringIO -from flask import Flask, request - -app = Flask(__name__) - - -@app.route("/xslt") -def bad(): - xsltQuery = request.args.get('xml', '') - xslt_root = etree.XML(xsltQuery) - f = StringIO('') - tree = etree.parse(f) - result_tree = tree.xslt(xslt_root) # Not OK diff --git a/python/ql/test/experimental/semmle/python/templates/Airspeed.py b/python/ql/test/experimental/semmle/python/templates/Airspeed.py deleted file mode 100644 index a41d70432a0..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/Airspeed.py +++ /dev/null @@ -1,10 +0,0 @@ -from bottle import Bottle, route, request, redirect, response -import airspeed - - -app = Bottle() - - -@route('/other') -def a(): - return airspeed.Template("sink") diff --git a/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.expected deleted file mode 100644 index e938211434c..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.expected +++ /dev/null @@ -1,2 +0,0 @@ -WARNING: Type SSTISink has been deprecated and may be removed in future (AirspeedSSTISinks.ql:4,6-14) -| Airspeed.py:10:30:10:35 | argument to airspeed.Template() | diff --git a/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.ql deleted file mode 100644 index e9c51ef11ad..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import experimental.semmle.python.templates.Airspeed - -from SSTISink s -select s diff --git a/python/ql/test/experimental/semmle/python/templates/Bottle.py b/python/ql/test/experimental/semmle/python/templates/Bottle.py deleted file mode 100644 index f6b2fec090e..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/Bottle.py +++ /dev/null @@ -1,17 +0,0 @@ -from bottle import Bottle, route, request, redirect, response, SimpleTemplate -from bottle import template as temp - - -app = Bottle() - - -@route('/other') -def a(): - template = "test" - tpl = SimpleTemplate(template) - - -@route('/other2') -def b(): - template = "test" - return temp(template, name='World') diff --git a/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.expected deleted file mode 100644 index 1802708c2de..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.expected +++ /dev/null @@ -1,3 +0,0 @@ -WARNING: Type SSTISink has been deprecated and may be removed in future (BottleSSTISinks.ql:4,6-14) -| Bottle.py:11:26:11:33 | argument to bottle.SimpleTemplate() | -| Bottle.py:17:17:17:24 | argument to bottle.template() | diff --git a/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.ql deleted file mode 100644 index c0ba59ef957..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import experimental.semmle.python.templates.Bottle - -from SSTISink s -select s diff --git a/python/ql/test/experimental/semmle/python/templates/Chameleon.py b/python/ql/test/experimental/semmle/python/templates/Chameleon.py deleted file mode 100644 index 6d96f0752a9..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/Chameleon.py +++ /dev/null @@ -1,5 +0,0 @@ -from chameleon import PageTemplate - - -def chameleon(): - template = PageTemplate("sink") diff --git a/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.expected deleted file mode 100644 index d6a46986f11..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.expected +++ /dev/null @@ -1,2 +0,0 @@ -WARNING: Type SSTISink has been deprecated and may be removed in future (ChameleonSSTISinks.ql:4,6-14) -| Chameleon.py:5:29:5:34 | argument to Chameleon.PageTemplate() | diff --git a/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.ql deleted file mode 100644 index ee9d41434af..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import experimental.semmle.python.templates.Chameleon - -from SSTISink s -select s diff --git a/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.expected deleted file mode 100644 index 3971b25e356..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.expected +++ /dev/null @@ -1,3 +0,0 @@ -WARNING: Type SSTISink has been deprecated and may be removed in future (CheetahSSTISinks.ql:4,6-14) -| CheetahSinks.py:10:21:10:26 | argument to Cheetah.Template.Template() | -| CheetahSinks.py:20:20:20:25 | argument to Cheetah.Template.Template() | diff --git a/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.ql deleted file mode 100644 index 10c6c79a4d5..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import experimental.semmle.python.templates.Cheetah - -from SSTISink s -select s diff --git a/python/ql/test/experimental/semmle/python/templates/CheetahSinks.py b/python/ql/test/experimental/semmle/python/templates/CheetahSinks.py deleted file mode 100644 index 0bb3364a178..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/CheetahSinks.py +++ /dev/null @@ -1,20 +0,0 @@ -from bottle import Bottle, route, request, redirect, response, SimpleTemplate -from Cheetah.Template import Template - - -app = Bottle() - - -@route('/other') -def a(): - return Template("sink") - - -class Template3(Template): - title = 'Hello World Example!' - contents = 'Hello World!' - - -@route('/other2') -def b(): - t3 = Template3("sink") diff --git a/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.expected deleted file mode 100644 index 50ebb008209..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.expected +++ /dev/null @@ -1,2 +0,0 @@ -WARNING: Type SSTISink has been deprecated and may be removed in future (ChevronSSTISinks.ql:4,6-14) -| ChevronSinks.py:10:27:10:32 | argument to chevron.render() | diff --git a/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.ql deleted file mode 100644 index 545c1f8f79a..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import experimental.semmle.python.templates.Chevron - -from SSTISink s -select s diff --git a/python/ql/test/experimental/semmle/python/templates/ChevronSinks.py b/python/ql/test/experimental/semmle/python/templates/ChevronSinks.py deleted file mode 100644 index 26d35708bb6..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/ChevronSinks.py +++ /dev/null @@ -1,22 +0,0 @@ -from bottle import Bottle, route, request, redirect, response, SimpleTemplate -import chevron - - -app = Bottle() - - -@route('/other') -def a(): - return chevron.render("sink", {"key": "value"}) - - -@route('/other2') -def b(): - sink = { - 'template': "template", - - 'data': { - 'key': 'value' - } - } - return chevron.render(**sink) diff --git a/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.expected deleted file mode 100644 index a38fdbc323f..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.expected +++ /dev/null @@ -1,2 +0,0 @@ -WARNING: Type SSTISink has been deprecated and may be removed in future (DjangoSSTISinks.ql:4,6-14) -| DjangoTemplates.py:9:18:9:25 | argument to Django.template() | diff --git a/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.ql deleted file mode 100644 index eecd31aeb87..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import experimental.semmle.python.templates.DjangoTemplate - -from SSTISink s -select s diff --git a/python/ql/test/experimental/semmle/python/templates/DjangoTemplates.py b/python/ql/test/experimental/semmle/python/templates/DjangoTemplates.py deleted file mode 100644 index 981109bf7dc..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/DjangoTemplates.py +++ /dev/null @@ -1,39 +0,0 @@ -from django.urls import path -from django.http import HttpResponse -from django.template import Template, Context, Engine, engines - - -def dj(request): - # Load the template - template = request.GET['template'] - t = Template(template) - ctx = Context(locals()) - html = t.render(ctx) - return HttpResponse(html) - - -def djEngine(request): - # Load the template - template = request.GET['template'] - - django_engine = engines['django'] - t = django_engine.from_string(template) - ctx = Context(locals()) - html = t.render(ctx) - return HttpResponse(html) - - -def djEngineJinja(request): - # Load the template - template = request.GET['template'] - - django_engine = engines['jinja'] - t = django_engine.from_string(template) - ctx = Context(locals()) - html = t.render(ctx) - return HttpResponse(html) - - -urlpatterns = [ - path('', dj) -] diff --git a/python/ql/test/experimental/semmle/python/templates/Genshi.py b/python/ql/test/experimental/semmle/python/templates/Genshi.py deleted file mode 100644 index 7c46a2b31dc..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/Genshi.py +++ /dev/null @@ -1,10 +0,0 @@ - - -def genshi1(): - from genshi.template import MarkupTemplate - tmpl = MarkupTemplate('sink') - - -def genshi2(): - from genshi.template import TextTemplate - tmpl = TextTemplate('sink') \ No newline at end of file diff --git a/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.expected deleted file mode 100644 index cfc22364413..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.expected +++ /dev/null @@ -1,3 +0,0 @@ -WARNING: Type SSTISink has been deprecated and may be removed in future (GenshiSSTISinks.ql:4,6-14) -| Genshi.py:5:27:5:32 | argument to genshi.template.MarkupTemplate() | -| Genshi.py:10:25:10:30 | argument to genshi.template.TextTemplate() | diff --git a/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.ql deleted file mode 100644 index f0d87e97ec1..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import experimental.semmle.python.templates.Genshi - -from SSTISink s -select s diff --git a/python/ql/test/experimental/semmle/python/templates/Jinja2Templates.py b/python/ql/test/experimental/semmle/python/templates/Jinja2Templates.py deleted file mode 100644 index e52538d4946..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/Jinja2Templates.py +++ /dev/null @@ -1,17 +0,0 @@ -from jinja2 import Template as Jinja2_Template -from jinja2 import Environment, DictLoader, escape - - -def jinja(): - t = Jinja2_Template("sink") - - -def jinja2(): - random = "esdad" + "asdad" - t = Jinja2_Template(random) - - -def jinja3(): - random = 1234 - t = Jinja2_Template("sink"+random) - diff --git a/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.expected deleted file mode 100644 index 7b91c934947..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.expected +++ /dev/null @@ -1,4 +0,0 @@ -WARNING: Type SSTISink has been deprecated and may be removed in future (JinjaSSTISinks.ql:4,6-14) -| Jinja2Templates.py:6:25:6:30 | argument to jinja2.Template() | -| Jinja2Templates.py:11:25:11:30 | argument to jinja2.Template() | -| Jinja2Templates.py:16:25:16:37 | argument to jinja2.Template() | diff --git a/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.ql deleted file mode 100644 index ca80d8bc570..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import experimental.semmle.python.templates.Jinja - -from SSTISink s -select s diff --git a/python/ql/test/experimental/semmle/python/templates/Mako.py b/python/ql/test/experimental/semmle/python/templates/Mako.py deleted file mode 100644 index 3af60b164ea..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/Mako.py +++ /dev/null @@ -1,5 +0,0 @@ - - -def mako(): - from mako.template import Template - mytemplate = Template("sink") diff --git a/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.expected deleted file mode 100644 index 005e14f218a..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.expected +++ /dev/null @@ -1,2 +0,0 @@ -WARNING: Type SSTISink has been deprecated and may be removed in future (MakoSSTISinks.ql:4,6-14) -| Mako.py:5:27:5:32 | argument to mako.template.Template() | diff --git a/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.ql deleted file mode 100644 index eed89420c54..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import experimental.semmle.python.templates.Mako - -from SSTISink s -select s diff --git a/python/ql/test/experimental/semmle/python/templates/TRender.py b/python/ql/test/experimental/semmle/python/templates/TRender.py deleted file mode 100644 index 6ed5a799942..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/TRender.py +++ /dev/null @@ -1,6 +0,0 @@ - - -def trender(): - from trender import TRender - template = '@greet world!' - compiled = TRender(template) diff --git a/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.expected deleted file mode 100644 index 26dea55a6c8..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.expected +++ /dev/null @@ -1,2 +0,0 @@ -WARNING: Type SSTISink has been deprecated and may be removed in future (TRenderSSTISinks.ql:4,6-14) -| TRender.py:6:24:6:31 | argument to trender.TRender() | diff --git a/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.ql deleted file mode 100644 index ec3a1bba57f..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python -import experimental.semmle.python.templates.TRender - -from SSTISink s -select s diff --git a/python/ql/test/experimental/semmle/python/templates/options b/python/ql/test/experimental/semmle/python/templates/options deleted file mode 100644 index c3bc9413072..00000000000 --- a/python/ql/test/experimental/semmle/python/templates/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --max-import-depth=3 -p ../../../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/SanitizedEdges.expected b/python/ql/test/library-tests/examples/custom-sanitizer/SanitizedEdges.expected deleted file mode 100644 index 22c6f68f1d7..00000000000 --- a/python/ql/test/library-tests/examples/custom-sanitizer/SanitizedEdges.expected +++ /dev/null @@ -1,23 +0,0 @@ -| MySanitizerHandlingNot | externally controlled string | test.py:13 | Pi(s_0) [true] | -| MySanitizerHandlingNot | externally controlled string | test.py:18 | Pi(s_5) [false] | -| MySanitizerHandlingNot | externally controlled string | test.py:28 | Pi(s_0) [true] | -| MySanitizerHandlingNot | externally controlled string | test.py:34 | Pi(s_10) [true] | -| MySanitizerHandlingNot | externally controlled string | test.py:40 | Pi(s_12) [false] | -| MySanitizerHandlingNot | externally controlled string | test.py:50 | Pi(s_0) [true] | -| MySanitizerHandlingNot | externally controlled string | test.py:56 | Pi(s_10) [true] | -| MySanitizerHandlingNot | externally controlled string | test.py:62 | Pi(s_12) [false] | -| MySanitizerHandlingNot | externally controlled string | test.py:76 | Pi(s_3) [true] | -| MySanitizerHandlingNot | externally controlled string | test.py:82 | Pi(s_0) [true] | -| MySanitizerHandlingNot | externally controlled string | test.py:87 | Pi(s_5) [false] | -| MySanitizerHandlingNot | externally controlled string | test.py:97 | Pi(s_0) [true] | -| MySanitizerHandlingNot | externally controlled string | test.py:102 | Pi(s_7) [true] | -| MySanitizerHandlingNot | externally controlled string | test.py:107 | Pi(s_12) [true] | -| MySimpleSanitizer | externally controlled string | test.py:13 | Pi(s_0) [true] | -| MySimpleSanitizer | externally controlled string | test.py:28 | Pi(s_0) [true] | -| MySimpleSanitizer | externally controlled string | test.py:34 | Pi(s_10) [true] | -| MySimpleSanitizer | externally controlled string | test.py:50 | Pi(s_0) [true] | -| MySimpleSanitizer | externally controlled string | test.py:56 | Pi(s_10) [true] | -| MySimpleSanitizer | externally controlled string | test.py:76 | Pi(s_3) [true] | -| MySimpleSanitizer | externally controlled string | test.py:97 | Pi(s_0) [true] | -| MySimpleSanitizer | externally controlled string | test.py:102 | Pi(s_7) [true] | -| MySimpleSanitizer | externally controlled string | test.py:107 | Pi(s_12) [true] | diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/SanitizedEdges.ql b/python/ql/test/library-tests/examples/custom-sanitizer/SanitizedEdges.ql deleted file mode 100644 index d523f79a963..00000000000 --- a/python/ql/test/library-tests/examples/custom-sanitizer/SanitizedEdges.ql +++ /dev/null @@ -1,6 +0,0 @@ -import python -import Taint - -from Sanitizer s, TaintKind taint, PyEdgeRefinement test -where s.sanitizingEdge(taint, test) -select s, taint, test.getTest().getLocation().toString(), test.getRepresentation() diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll b/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll deleted file mode 100644 index 343caa1131f..00000000000 --- a/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll +++ /dev/null @@ -1,77 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted - -class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "taint source" } -} - -class MySimpleSanitizer extends Sanitizer { - MySimpleSanitizer() { this = "MySimpleSanitizer" } - - /* - * The test `if is_safe(arg):` sanitizes `arg` on its `true` edge. - * - * Can't handle `if not is_safe(arg):` :\ that's why it's called MySimpleSanitizer - */ - - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - taint instanceof ExternalStringKind and - exists(CallNode call | test.getTest() = call and test.getSense() = true | - call = Value::named("test.is_safe").getACall() and - test.getInput().getAUse() = call.getAnArg() - ) - } -} - -class MySanitizerHandlingNot extends Sanitizer { - MySanitizerHandlingNot() { this = "MySanitizerHandlingNot" } - - /** Holds if the test `if is_safe(arg):` sanitizes `arg` on its `true` edge. */ - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - taint instanceof ExternalStringKind and - clears_taint_on_true(test.getTest(), test.getSense(), test) - } -} - -/** - * Helper predicate that recurses into any nesting of `not` - * - * To reduce the number of tuples this predicate holds for, we include the `PyEdgeRefinement` and - * ensure that `test` is a part of this `PyEdgeRefinement` (instead of just taking the - * `edge_refinement.getInput().getAUse()` part as a part of the predicate). Without including - * `PyEdgeRefinement` as an argument *any* `CallNode c` to `test.is_safe` would be a result of - * this predicate, since the tuple where `test = c` and `sense = true` would hold. - */ -private predicate clears_taint_on_true( - ControlFlowNode test, boolean sense, PyEdgeRefinement edge_refinement -) { - edge_refinement.getTest().getNode().(Expr).getASubExpression*() = test.getNode() and - ( - test = Value::named("test.is_safe").getACall() and - edge_refinement.getInput().getAUse() = test.(CallNode).getAnArg() and - sense = true - or - test.(UnaryExprNode).getNode().getOp() instanceof Not and - exists(ControlFlowNode nested_test | - nested_test = test.(UnaryExprNode).getOperand() and - clears_taint_on_true(nested_test, sense.booleanNot(), edge_refinement) - ) - ) -} - -class TestConfig extends TaintTracking::Configuration { - TestConfig() { this = "TestConfig" } - - override predicate isSanitizer(Sanitizer sanitizer) { - sanitizer instanceof MySanitizerHandlingNot - } - - override predicate isSource(TaintTracking::Source source) { source instanceof SimpleSource } - - override predicate isSink(TaintTracking::Sink sink) { none() } -} diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.expected b/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.expected deleted file mode 100644 index 269eb47a37f..00000000000 --- a/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.expected +++ /dev/null @@ -1,28 +0,0 @@ -| test.py:14 | test_basic | s | | ok | -| test.py:16 | test_basic | s | externally controlled string | ok | -| test.py:19 | test_basic | s | externally controlled string | ok | -| test.py:21 | test_basic | s | | ok | -| test.py:29 | test_or | s | externally controlled string | ok | -| test.py:31 | test_or | s | externally controlled string | ok | -| test.py:35 | test_or | s | externally controlled string | ok | -| test.py:37 | test_or | s | externally controlled string | ok | -| test.py:41 | test_or | s | externally controlled string | ok | -| test.py:43 | test_or | s | externally controlled string | ok | -| test.py:51 | test_and | s | | ok | -| test.py:53 | test_and | s | externally controlled string | ok | -| test.py:57 | test_and | s | externally controlled string | ok | -| test.py:59 | test_and | s | | ok | -| test.py:63 | test_and | s | externally controlled string | ok | -| test.py:65 | test_and | s | | ok | -| test.py:73 | test_tricky | s | externally controlled string | failure | -| test.py:77 | test_tricky | s_ | externally controlled string | failure | -| test.py:83 | test_nesting_not | s | | ok | -| test.py:85 | test_nesting_not | s | externally controlled string | ok | -| test.py:88 | test_nesting_not | s | externally controlled string | ok | -| test.py:90 | test_nesting_not | s | | ok | -| test.py:98 | test_nesting_not_with_and_true | s | externally controlled string | ok | -| test.py:100 | test_nesting_not_with_and_true | s | | ok | -| test.py:103 | test_nesting_not_with_and_true | s | | ok | -| test.py:105 | test_nesting_not_with_and_true | s | externally controlled string | ok | -| test.py:108 | test_nesting_not_with_and_true | s | externally controlled string | ok | -| test.py:110 | test_nesting_not_with_and_true | s | | ok | diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql b/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql deleted file mode 100644 index 431e96e4d5d..00000000000 --- a/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql +++ /dev/null @@ -1,31 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import Taint - -from - Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, - string taint_string -where - call.getLocation().getFile().getShortName() = "test.py" and - ( - call.getFunc().(Name).getId() = "ensure_tainted" and - expected_taint = true - or - call.getFunc().(Name).getId() = "ensure_not_tainted" and - expected_taint = false - ) and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "" and - has_taint = false - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) and - has_taint = true - ) and - if expected_taint = has_taint then test_res = "ok" else test_res = "failure" -// if expected_taint = has_taint then test_res = "✓" else test_res = "✕" -select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string, test_res diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/test.py b/python/ql/test/library-tests/examples/custom-sanitizer/test.py deleted file mode 100644 index e0bf29f4ee6..00000000000 --- a/python/ql/test/library-tests/examples/custom-sanitizer/test.py +++ /dev/null @@ -1,110 +0,0 @@ -def random_choice(): - return bool(GLOBAL_UNKOWN_VAR) - -def is_safe(arg): - return UNKNOWN_FUNC(arg) - -def true_func(): - return True - -def test_basic(): - s = TAINTED_STRING - - if is_safe(s): - ensure_not_tainted(s) - else: - ensure_tainted(s) - - if not is_safe(s): - ensure_tainted(s) - else: - ensure_not_tainted(s) - - -def test_or(): - s = TAINTED_STRING - - # x or y - if is_safe(s) or random_choice(): - ensure_tainted(s) # might be tainted - else: - ensure_tainted(s) # must be tainted - - # not (x or y) - if not(is_safe(s) or random_choice()): - ensure_tainted(s) # must be tainted - else: - ensure_tainted(s) # might be tainted - - # not (x or y) == not x and not y [de Morgan's laws] - if not is_safe(s) and not random_choice(): - ensure_tainted(s) # must be tainted - else: - ensure_tainted(s) # might be tainted - - -def test_and(): - s = TAINTED_STRING - - # x and y - if is_safe(s) and random_choice(): - ensure_not_tainted(s) # must not be tainted - else: - ensure_tainted(s) # might be tainted - - # not (x and y) - if not(is_safe(s) and random_choice()): - ensure_tainted(s) # might be tainted - else: - ensure_not_tainted(s) - - # not (x and y) == not x or not y [de Morgan's laws] - if not is_safe(s) or not random_choice(): - ensure_tainted(s) # might be tainted - else: - ensure_not_tainted(s) - - -def test_tricky(): - s = TAINTED_STRING - - x = is_safe(s) - if x: - ensure_not_tainted(s) # FP - - s_ = s - if is_safe(s): - ensure_not_tainted(s_) # FP - -def test_nesting_not(): - s = TAINTED_STRING - - if not(not(is_safe(s))): - ensure_not_tainted(s) - else: - ensure_tainted(s) - - if not(not(not(is_safe(s)))): - ensure_tainted(s) - else: - ensure_not_tainted(s) - -# Adding `and True` makes the sanitizer trigger when it would otherwise not. See output in -# SanitizedEdges.expected and compare with `test_nesting_not` and `test_basic` -def test_nesting_not_with_and_true(): - s = TAINTED_STRING - - if not(is_safe(s) and True): - ensure_tainted(s) - else: - ensure_not_tainted(s) - - if not(not(is_safe(s) and True)): - ensure_not_tainted(s) - else: - ensure_tainted(s) - - if not(not(not(is_safe(s) and True))): - ensure_tainted(s) - else: - ensure_not_tainted(s) diff --git a/python/ql/test/library-tests/security/command-execution/CommandSinks.expected b/python/ql/test/library-tests/security/command-execution/CommandSinks.expected deleted file mode 100644 index 425a0471399..00000000000 --- a/python/ql/test/library-tests/security/command-execution/CommandSinks.expected +++ /dev/null @@ -1,18 +0,0 @@ -WARNING: Type CommandSink has been deprecated and may be removed in future (CommandSinks.ql:4,6-17) -| fabric_v1_test.py:8:7:8:28 | FabricV1Commands | externally controlled string | -| fabric_v1_test.py:9:5:9:27 | FabricV1Commands | externally controlled string | -| fabric_v1_test.py:10:6:10:38 | FabricV1Commands | externally controlled string | -| fabric_v2_test.py:10:16:10:25 | InvokeContextRun | externally controlled string | -| fabric_v2_test.py:12:15:12:36 | InvokeContextRun | externally controlled string | -| fabric_v2_test.py:16:45:16:54 | FabricGroupRun | externally controlled string | -| fabric_v2_test.py:21:10:21:13 | FabricGroupRun | externally controlled string | -| fabric_v2_test.py:31:14:31:41 | InvokeContextRun | externally controlled string | -| fabric_v2_test.py:33:15:33:64 | InvokeContextRun | externally controlled string | -| invoke_test.py:8:12:8:21 | InvokeRun | externally controlled string | -| invoke_test.py:9:20:9:40 | InvokeRun | externally controlled string | -| invoke_test.py:12:17:12:24 | InvokeRun | externally controlled string | -| invoke_test.py:13:25:13:32 | InvokeRun | externally controlled string | -| invoke_test.py:17:11:17:40 | InvokeContextRun | externally controlled string | -| invoke_test.py:21:11:21:32 | InvokeContextRun | externally controlled string | -| invoke_test.py:27:11:27:25 | InvokeContextRun | externally controlled string | -| invoke_test.py:32:11:32:25 | InvokeContextRun | externally controlled string | diff --git a/python/ql/test/library-tests/security/command-execution/CommandSinks.ql b/python/ql/test/library-tests/security/command-execution/CommandSinks.ql deleted file mode 100644 index 797b527d568..00000000000 --- a/python/ql/test/library-tests/security/command-execution/CommandSinks.ql +++ /dev/null @@ -1,6 +0,0 @@ -import python -import semmle.python.security.injection.Command - -from CommandSink sink, TaintKind kind -where sink.sinks(kind) -select sink, kind diff --git a/python/ql/test/library-tests/security/command-execution/fabric-LICENSE b/python/ql/test/library-tests/security/command-execution/fabric-LICENSE deleted file mode 100644 index 10e0dcedd55..00000000000 --- a/python/ql/test/library-tests/security/command-execution/fabric-LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2020 Jeff Forcier. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/python/ql/test/library-tests/security/command-execution/fabric_v1_test.py b/python/ql/test/library-tests/security/command-execution/fabric_v1_test.py deleted file mode 100644 index 82f34dde6d2..00000000000 --- a/python/ql/test/library-tests/security/command-execution/fabric_v1_test.py +++ /dev/null @@ -1,10 +0,0 @@ -"""tests for the 'fabric' package (v1.x) - -See http://docs.fabfile.org/en/1.14/tutorial.html -""" - -from fabric.api import run, local, sudo - -local('echo local execution') -run('echo remote execution') -sudo('echo remote execution with sudo') diff --git a/python/ql/test/library-tests/security/command-execution/fabric_v2_test.py b/python/ql/test/library-tests/security/command-execution/fabric_v2_test.py deleted file mode 100644 index 0854db3ea0b..00000000000 --- a/python/ql/test/library-tests/security/command-execution/fabric_v2_test.py +++ /dev/null @@ -1,33 +0,0 @@ -"""tests for the 'fabric' package (v2.x) - -Most of these examples are taken from the fabric documentation: http://docs.fabfile.org/en/2.5/getting-started.html -See fabric-LICENSE for its' license. -""" - -from fabric import Connection - -c = Connection('web1') -result = c.run('uname -s') - -c.run(command='echo run with kwargs') - - -from fabric import SerialGroup as Group -results = Group('web1', 'web2', 'mac1').run('uname -s') - - -from fabric import SerialGroup as Group -pool = Group('web1', 'web2', 'web3') -pool.run('ls') - - - -# using the 'fab' command-line tool - -from fabric import task - -@task -def upload_and_unpack(c): - if c.run('test -f /opt/mydata/myfile', warn=True).failed: - c.put('myfiles.tgz', '/opt/mydata') - c.run('tar -C /opt/mydata -xzvf /opt/mydata/myfiles.tgz') diff --git a/python/ql/test/library-tests/security/command-execution/invoke_test.py b/python/ql/test/library-tests/security/command-execution/invoke_test.py deleted file mode 100644 index 9bc2213b617..00000000000 --- a/python/ql/test/library-tests/security/command-execution/invoke_test.py +++ /dev/null @@ -1,32 +0,0 @@ -"""tests for the 'invoke' package - -see https://www.pyinvoke.org/ -""" - -import invoke - -invoke.run('echo run') -invoke.run(command='echo run with kwarg') - -def with_sudo(): - invoke.sudo('whoami') - invoke.sudo(command='whoami') - -def manual_context(): - c = invoke.Context() - c.run('echo run from manual context') -manual_context() - -def foo_helper(c): - c.run('echo from foo_helper') - -# for use with the 'invoke' command-line tool -@invoke.task -def foo(c): - # 'c' is a invoke.context.Context - c.run('echo task foo') - foo_helper(c) - -@invoke.task() -def bar(c): - c.run('echo task bar') diff --git a/python/ql/test/library-tests/security/command-execution/options b/python/ql/test/library-tests/security/command-execution/options deleted file mode 100644 index 1d132442a3b..00000000000 --- a/python/ql/test/library-tests/security/command-execution/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=2 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll b/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll deleted file mode 100644 index 7d1a812be92..00000000000 --- a/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll +++ /dev/null @@ -1,24 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted -import semmle.python.security.injection.Command - -class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "taint source" } -} - -class FabricExecuteTestConfiguration extends TaintTracking::Configuration { - FabricExecuteTestConfiguration() { this = "FabricExecuteTestConfiguration" } - - override predicate isSource(TaintTracking::Source source) { source instanceof SimpleSource } - - override predicate isSink(TaintTracking::Sink sink) { sink instanceof CommandSink } - - override predicate isExtension(TaintTracking::Extension extension) { - extension instanceof FabricExecuteExtension - } -} diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected b/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected deleted file mode 100644 index edd58bbb75f..00000000000 --- a/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected +++ /dev/null @@ -1,10 +0,0 @@ -| test.py:8 | ok | unsafe | cmd | externally controlled string | -| test.py:8 | ok | unsafe | cmd2 | externally controlled string | -| test.py:9 | ok | unsafe | safe_arg | | -| test.py:9 | ok | unsafe | safe_optional | | -| test.py:16 | ok | unsafe | cmd | externally controlled string | -| test.py:16 | ok | unsafe | cmd2 | externally controlled string | -| test.py:17 | ok | unsafe | safe_arg | | -| test.py:17 | ok | unsafe | safe_optional | | -| test.py:23 | ok | some_http_handler | cmd | externally controlled string | -| test.py:23 | ok | some_http_handler | cmd2 | externally controlled string | diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql b/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql deleted file mode 100644 index 7b9c6025c9d..00000000000 --- a/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql +++ /dev/null @@ -1,33 +0,0 @@ -import python -import semmle.python.security.TaintTracking -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted -import Taint - -from - Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, - string taint_string -where - call.getLocation().getFile().getShortName() = "test.py" and - ( - call.getFunc().(Name).getId() = "ensure_tainted" and - expected_taint = true - or - call.getFunc().(Name).getId() = "ensure_not_tainted" and - expected_taint = false - ) and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "" and - has_taint = false - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) and - has_taint = true - ) and - if expected_taint = has_taint then test_res = "ok " else test_res = "fail" -// if expected_taint = has_taint then test_res = "✓" else test_res = "✕" -select arg.getLocation().toString(), test_res, call.getScope().(Function).getName(), arg.toString(), - taint_string diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/options b/python/ql/test/library-tests/security/fabric-v1-execute/options deleted file mode 100644 index 1d132442a3b..00000000000 --- a/python/ql/test/library-tests/security/fabric-v1-execute/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=2 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/test.py b/python/ql/test/library-tests/security/fabric-v1-execute/test.py deleted file mode 100644 index 7a1cd9ab377..00000000000 --- a/python/ql/test/library-tests/security/fabric-v1-execute/test.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Test that shows fabric.api.execute propagates taint""" - -from fabric.api import run, execute - - -def unsafe(cmd, safe_arg, cmd2=None, safe_optional=5): - run('./venv/bin/activate && {}'.format(cmd)) - ensure_tainted(cmd, cmd2) - ensure_not_tainted(safe_arg, safe_optional) - - -class Foo(object): - - def unsafe(self, cmd, safe_arg, cmd2=None, safe_optional=5): - run('./venv/bin/activate && {}'.format(cmd)) - ensure_tainted(cmd, cmd2) - ensure_not_tainted(safe_arg, safe_optional) - - -def some_http_handler(): - cmd = TAINTED_STRING - cmd2 = TAINTED_STRING - ensure_tainted(cmd, cmd2) - - execute(unsafe, cmd=cmd, safe_arg='safe_arg', cmd2=cmd2) - - foo = Foo() - execute(foo.unsafe, cmd, 'safe_arg', cmd2) diff --git a/python/ql/test/library-tests/taint/collections/Taint.qll b/python/ql/test/library-tests/taint/collections/Taint.qll deleted file mode 100644 index 010b9738c5c..00000000000 --- a/python/ql/test/library-tests/taint/collections/Taint.qll +++ /dev/null @@ -1,27 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted - -class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "taint source" } -} - -class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - - override string toString() { result = "list taint source" } -} - -class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - - override string toString() { result = "dict taint source" } -} diff --git a/python/ql/test/library-tests/taint/collections/TestStep.expected b/python/ql/test/library-tests/taint/collections/TestStep.expected deleted file mode 100644 index a9591db0b9f..00000000000 --- a/python/ql/test/library-tests/taint/collections/TestStep.expected +++ /dev/null @@ -1,63 +0,0 @@ -| Taint [externally controlled string] | test.py:9 | test.py:9:20:9:35 | List | | --> | Taint [externally controlled string] | test.py:14 | test.py:14:14:14:25 | tainted_list | | -| Taint [externally controlled string] | test.py:9 | test.py:9:20:9:35 | List | | --> | Taint [externally controlled string] | test.py:20 | test.py:20:15:20:26 | tainted_list | | -| Taint [externally controlled string] | test.py:9 | test.py:9:20:9:35 | List | | --> | Taint [externally controlled string] | test.py:21 | test.py:21:13:21:24 | tainted_list | | -| Taint [externally controlled string] | test.py:9 | test.py:9:20:9:35 | List | | --> | Taint [externally controlled string] | test.py:22 | test.py:22:19:22:30 | tainted_list | | -| Taint [externally controlled string] | test.py:10 | test.py:10:22:10:36 | Tuple | | --> | Taint [externally controlled string] | test.py:15 | test.py:15:14:15:26 | tainted_tuple | | -| Taint [externally controlled string] | test.py:14 | test.py:14:9:14:26 | list() | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:10:23:10 | a | | -| Taint [externally controlled string] | test.py:14 | test.py:14:14:14:25 | tainted_list | | --> | Taint [externally controlled string] | test.py:14 | test.py:14:9:14:26 | list() | | -| Taint [externally controlled string] | test.py:15 | test.py:15:9:15:27 | list() | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:13:23:13 | b | | -| Taint [externally controlled string] | test.py:15 | test.py:15:14:15:26 | tainted_tuple | | --> | Taint [externally controlled string] | test.py:15 | test.py:15:9:15:27 | list() | | -| Taint [externally controlled string] | test.py:17 | test.py:17:9:17:35 | list() | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:19:23:19 | d | | -| Taint [externally controlled string] | test.py:17 | test.py:17:14:17:34 | Attribute() | | --> | Taint [externally controlled string] | test.py:17 | test.py:17:9:17:35 | list() | | -| Taint [externally controlled string] | test.py:20 | test.py:20:9:20:27 | tuple() | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:25:23:25 | f | | -| Taint [externally controlled string] | test.py:20 | test.py:20:15:20:26 | tainted_list | | --> | Taint [externally controlled string] | test.py:20 | test.py:20:9:20:27 | tuple() | | -| Taint [externally controlled string] | test.py:21 | test.py:21:9:21:25 | set() | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:28:23:28 | g | | -| Taint [externally controlled string] | test.py:21 | test.py:21:13:21:24 | tainted_list | | --> | Taint [externally controlled string] | test.py:21 | test.py:21:9:21:25 | set() | | -| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:27 | test.py:27:9:27:20 | tainted_list | | -| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:28 | test.py:28:9:28:20 | tainted_list | | -| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:29 | test.py:29:9:29:20 | tainted_list | | -| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:30 | test.py:30:9:30:20 | tainted_list | | -| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:31 | test.py:31:15:31:26 | tainted_list | | -| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:33 | test.py:33:14:33:25 | tainted_list | | -| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:35 | test.py:35:23:35:34 | tainted_list | | -| Taint [externally controlled string] | test.py:27 | test.py:27:9:27:20 | tainted_list | | --> | Taint externally controlled string | test.py:27 | test.py:27:9:27:23 | Subscript | | -| Taint [externally controlled string] | test.py:28 | test.py:28:9:28:20 | tainted_list | | --> | Taint externally controlled string | test.py:28 | test.py:28:9:28:23 | Subscript | | -| Taint [externally controlled string] | test.py:29 | test.py:29:9:29:20 | tainted_list | | --> | Taint [externally controlled string] | test.py:29 | test.py:29:9:29:25 | Subscript | | -| Taint [externally controlled string] | test.py:29 | test.py:29:9:29:25 | Subscript | | --> | Taint [externally controlled string] | test.py:32 | test.py:32:16:32:16 | c | | -| Taint [externally controlled string] | test.py:30 | test.py:30:9:30:20 | tainted_list | | --> | Taint [externally controlled string] | test.py:30 | test.py:30:9:30:27 | Attribute() | | -| Taint [externally controlled string] | test.py:30 | test.py:30:9:30:27 | Attribute() | | --> | Taint [externally controlled string] | test.py:32 | test.py:32:19:32:19 | d | | -| Taint [externally controlled string] | test.py:31 | test.py:31:15:31:26 | tainted_list | | --> | Taint externally controlled string | test.py:32 | test.py:32:22:32:22 | e | | -| Taint [externally controlled string] | test.py:31 | test.py:31:15:31:26 | tainted_list | | --> | Taint externally controlled string | test.py:32 | test.py:32:25:32:25 | f | | -| Taint [externally controlled string] | test.py:31 | test.py:31:15:31:26 | tainted_list | | --> | Taint externally controlled string | test.py:32 | test.py:32:28:32:28 | g | | -| Taint [externally controlled string] | test.py:33 | test.py:33:14:33:25 | tainted_list | | --> | Taint externally controlled string | test.py:33 | test.py:33:5:33:26 | For | | -| Taint [externally controlled string] | test.py:35 | test.py:35:14:35:35 | reversed() | | --> | Taint externally controlled string | test.py:35 | test.py:35:5:35:36 | For | | -| Taint [externally controlled string] | test.py:35 | test.py:35:23:35:34 | tainted_list | | --> | Taint [externally controlled string] | test.py:35 | test.py:35:14:35:35 | reversed() | | -| Taint [externally controlled string] | test.py:44 | test.py:44:14:44:34 | Attribute() | | --> | Taint externally controlled string | test.py:44 | test.py:44:5:44:35 | For | | -| Taint externally controlled string | test.py:8 | test.py:8:22:8:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:9 | test.py:9:21:9:34 | tainted_string | | -| Taint externally controlled string | test.py:8 | test.py:8:22:8:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:10 | test.py:10:22:10:35 | tainted_string | | -| Taint externally controlled string | test.py:8 | test.py:8:22:8:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:11 | test.py:11:20:11:33 | tainted_string | | -| Taint externally controlled string | test.py:8 | test.py:8:22:8:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:12 | test.py:12:28:12:41 | tainted_string | | -| Taint externally controlled string | test.py:9 | test.py:9:21:9:34 | tainted_string | | --> | Taint [externally controlled string] | test.py:9 | test.py:9:20:9:35 | List | | -| Taint externally controlled string | test.py:10 | test.py:10:22:10:35 | tainted_string | | --> | Taint [externally controlled string] | test.py:10 | test.py:10:22:10:36 | Tuple | | -| Taint externally controlled string | test.py:12 | test.py:12:28:12:41 | tainted_string | | --> | Taint {externally controlled string} | test.py:12 | test.py:12:20:12:42 | Dict | | -| Taint externally controlled string | test.py:27 | test.py:27:9:27:23 | Subscript | | --> | Taint externally controlled string | test.py:32 | test.py:32:10:32:10 | a | | -| Taint externally controlled string | test.py:28 | test.py:28:9:28:23 | Subscript | | --> | Taint externally controlled string | test.py:32 | test.py:32:13:32:13 | b | | -| Taint externally controlled string | test.py:33 | test.py:33:5:33:26 | For | | --> | Taint externally controlled string | test.py:34 | test.py:34:14:34:14 | h | | -| Taint externally controlled string | test.py:35 | test.py:35:5:35:36 | For | | --> | Taint externally controlled string | test.py:36 | test.py:36:14:36:14 | i | | -| Taint externally controlled string | test.py:40 | test.py:40:9:40:28 | Subscript | | --> | Taint externally controlled string | test.py:43 | test.py:43:10:43:10 | a | | -| Taint externally controlled string | test.py:41 | test.py:41:9:41:23 | Subscript | | --> | Taint externally controlled string | test.py:43 | test.py:43:13:43:13 | b | | -| Taint externally controlled string | test.py:44 | test.py:44:5:44:35 | For | | --> | Taint externally controlled string | test.py:45 | test.py:45:14:45:14 | d | | -| Taint externally controlled string | test.py:62 | test.py:62:34:62:47 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:62 | test.py:62:5:62:47 | BinaryExpr | | -| Taint {externally controlled string} | test.py:12 | test.py:12:20:12:42 | Dict | | --> | Taint {externally controlled string} | test.py:17 | test.py:17:14:17:25 | tainted_dict | | -| Taint {externally controlled string} | test.py:12 | test.py:12:20:12:42 | Dict | | --> | Taint {externally controlled string} | test.py:18 | test.py:18:14:18:25 | tainted_dict | | -| Taint {externally controlled string} | test.py:17 | test.py:17:14:17:25 | tainted_dict | | --> | Taint [externally controlled string] | test.py:17 | test.py:17:14:17:34 | Attribute() | | -| Taint {externally controlled string} | test.py:39 | test.py:39:20:39:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:40 | test.py:40:9:40:20 | tainted_dict | | -| Taint {externally controlled string} | test.py:39 | test.py:39:20:39:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:41 | test.py:41:9:41:20 | tainted_dict | | -| Taint {externally controlled string} | test.py:39 | test.py:39:20:39:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:42 | test.py:42:9:42:20 | tainted_dict | | -| Taint {externally controlled string} | test.py:39 | test.py:39:20:39:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:44 | test.py:44:14:44:25 | tainted_dict | | -| Taint {externally controlled string} | test.py:39 | test.py:39:20:39:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:46 | test.py:46:17:46:28 | tainted_dict | | -| Taint {externally controlled string} | test.py:40 | test.py:40:9:40:20 | tainted_dict | | --> | Taint externally controlled string | test.py:40 | test.py:40:9:40:28 | Subscript | | -| Taint {externally controlled string} | test.py:41 | test.py:41:9:41:20 | tainted_dict | | --> | Taint externally controlled string | test.py:41 | test.py:41:9:41:23 | Subscript | | -| Taint {externally controlled string} | test.py:42 | test.py:42:9:42:20 | tainted_dict | | --> | Taint {externally controlled string} | test.py:42 | test.py:42:9:42:27 | Attribute() | | -| Taint {externally controlled string} | test.py:42 | test.py:42:9:42:27 | Attribute() | | --> | Taint {externally controlled string} | test.py:43 | test.py:43:16:43:16 | c | | -| Taint {externally controlled string} | test.py:44 | test.py:44:14:44:25 | tainted_dict | | --> | Taint [externally controlled string] | test.py:44 | test.py:44:14:44:34 | Attribute() | | diff --git a/python/ql/test/library-tests/taint/collections/TestStep.ql b/python/ql/test/library-tests/taint/collections/TestStep.ql deleted file mode 100644 index 177edce3498..00000000000 --- a/python/ql/test/library-tests/taint/collections/TestStep.ql +++ /dev/null @@ -1,11 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import Taint - -from TaintedNode n, TaintedNode s -where - n.getLocation().getFile().getShortName() = "test.py" and - s.getLocation().getFile().getShortName() = "test.py" and - s = n.getASuccessor() -select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getAstNode(), n.getContext(), - " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), s.getAstNode(), s.getContext() diff --git a/python/ql/test/library-tests/taint/collections/TestTaint.expected b/python/ql/test/library-tests/taint/collections/TestTaint.expected deleted file mode 100644 index aae51236e6d..00000000000 --- a/python/ql/test/library-tests/taint/collections/TestTaint.expected +++ /dev/null @@ -1,33 +0,0 @@ -| test.py:23 | test_construction | a | [externally controlled string] | -| test.py:23 | test_construction | b | [externally controlled string] | -| test.py:23 | test_construction | c | NO TAINT | -| test.py:23 | test_construction | d | [externally controlled string] | -| test.py:23 | test_construction | e | NO TAINT | -| test.py:23 | test_construction | f | [externally controlled string] | -| test.py:23 | test_construction | g | [externally controlled string] | -| test.py:23 | test_construction | h | NO TAINT | -| test.py:32 | test_access | a | externally controlled string | -| test.py:32 | test_access | b | externally controlled string | -| test.py:32 | test_access | c | [externally controlled string] | -| test.py:32 | test_access | d | [externally controlled string] | -| test.py:32 | test_access | e | externally controlled string | -| test.py:32 | test_access | f | externally controlled string | -| test.py:32 | test_access | g | externally controlled string | -| test.py:34 | test_access | h | externally controlled string | -| test.py:36 | test_access | i | externally controlled string | -| test.py:43 | test_dict_access | a | externally controlled string | -| test.py:43 | test_dict_access | b | externally controlled string | -| test.py:43 | test_dict_access | c | {externally controlled string} | -| test.py:45 | test_dict_access | d | externally controlled string | -| test.py:47 | test_dict_access | e | NO TAINT | -| test.py:58 | test_named_tuple | a | NO TAINT | -| test.py:58 | test_named_tuple | b | NO TAINT | -| test.py:58 | test_named_tuple | c | NO TAINT | -| test.py:58 | test_named_tuple | d | NO TAINT | -| test.py:58 | test_named_tuple | e | NO TAINT | -| test.py:58 | test_named_tuple | f | NO TAINT | -| test.py:67 | test_defaultdict | a | NO TAINT | -| test.py:67 | test_defaultdict | b | NO TAINT | -| test.py:67 | test_defaultdict | c | NO TAINT | -| test.py:69 | test_defaultdict | d | NO TAINT | -| test.py:71 | test_defaultdict | e | NO TAINT | diff --git a/python/ql/test/library-tests/taint/collections/TestTaint.ql b/python/ql/test/library-tests/taint/collections/TestTaint.ql deleted file mode 100644 index 47883578516..00000000000 --- a/python/ql/test/library-tests/taint/collections/TestTaint.ql +++ /dev/null @@ -1,19 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import Taint - -from Call call, Expr arg, string taint_string -where - call.getLocation().getFile().getShortName() = "test.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) - ) -select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string diff --git a/python/ql/test/library-tests/taint/collections/test.py b/python/ql/test/library-tests/taint/collections/test.py deleted file mode 100644 index 445effe19ce..00000000000 --- a/python/ql/test/library-tests/taint/collections/test.py +++ /dev/null @@ -1,71 +0,0 @@ -from collections import defaultdict, namedtuple - -# Use to show only interesting results in qltest output -def test(*args): - pass - -def test_construction(): - tainted_string = TAINTED_STRING - tainted_list = [tainted_string] - tainted_tuple = (tainted_string,) - tainted_set = {tainted_string} # TODO: set currently not handled - tainted_dict = {'key': tainted_string} - - a = list(tainted_list) - b = list(tainted_tuple) - c = list(tainted_set) # TODO: set currently not handled - d = list(tainted_dict.values()) - e = list(tainted_dict.items()) # TODO: dict.items() currently not handled - - f = tuple(tainted_list) - g = set(tainted_list) - h = frozenset(tainted_list) # TODO: frozenset constructor currently not handled - test(a, b, c, d, e, f, g, h) - -def test_access(): - tainted_list = TAINTED_LIST - a = tainted_list[0] - b = tainted_list[x] - c = tainted_list[y:z] - d = tainted_list.copy() - e, f, g = tainted_list - test(a, b, c, d, e, f, g) - for h in tainted_list: - test(h) - for i in reversed(tainted_list): - test(i) - -def test_dict_access(x): - tainted_dict = TAINTED_DICT - a = tainted_dict["name"] - b = tainted_dict[x] - c = tainted_dict.copy() - test(a, b, c) - for d in tainted_dict.values(): - test(d) - for _, e in tainted_dict.items(): # TODO: dict.items() currently not handled - test(e) - -def test_named_tuple(): # TODO: namedtuple currently not handled - Point = namedtuple('Point', ['x', 'y']) - point = Point(TAINTED_STRING, 'const') - - a = point[0] - b = point.x - c = point[1] - d = point.y - e, f = point - test(a, b, c, d, e, f) - -def test_defaultdict(key, x): # TODO: defaultdict currently not handled - tainted_default_dict = defaultdict(str) - tainted_default_dict[key] += TAINTED_STRING - - a = tainted_dict["name"] - b = tainted_dict[x] - c = tainted_dict.copy() - test(a, b, c) - for d in tainted_dict.values(): - test(d) - for _, e in tainted_dict.items(): - test(e) diff --git a/python/ql/test/library-tests/taint/config/RockPaperScissors.ql b/python/ql/test/library-tests/taint/config/RockPaperScissors.ql index 8d6170351f1..9fc258159ae 100644 --- a/python/ql/test/library-tests/taint/config/RockPaperScissors.ql +++ b/python/ql/test/library-tests/taint/config/RockPaperScissors.ql @@ -5,7 +5,6 @@ import python import semmle.python.dataflow.TaintTracking import TaintLib -import semmle.python.security.Paths from RockPaperScissorConfig config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) diff --git a/python/ql/test/library-tests/taint/config/Simple.ql b/python/ql/test/library-tests/taint/config/Simple.ql index 9a87a67c9f1..7617ec0a434 100644 --- a/python/ql/test/library-tests/taint/config/Simple.ql +++ b/python/ql/test/library-tests/taint/config/Simple.ql @@ -5,7 +5,6 @@ import python import semmle.python.dataflow.TaintTracking import TaintLib -import semmle.python.security.Paths from SimpleConfig config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) diff --git a/python/ql/test/library-tests/taint/example/ExampleConfig.ql b/python/ql/test/library-tests/taint/example/ExampleConfig.ql index e406fc73e21..ea1dd879a95 100644 --- a/python/ql/test/library-tests/taint/example/ExampleConfig.ql +++ b/python/ql/test/library-tests/taint/example/ExampleConfig.ql @@ -7,7 +7,6 @@ import python import DilbertConfig -import semmle.python.security.Paths from DilbertConfig config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestNode.expected b/python/ql/test/library-tests/taint/exception_traceback/TestNode.expected deleted file mode 100644 index b0b2a23b14b..00000000000 --- a/python/ql/test/library-tests/taint/exception_traceback/TestNode.expected +++ /dev/null @@ -1,27 +0,0 @@ -| test.py:10:11:10:47 | test.py:10 | MyException() | exception.kind | -| test.py:15:25:15:25 | test.py:15 | e | exception.kind | -| test.py:16:13:16:34 | test.py:16 | Attribute() | exception.info | -| test.py:17:15:17:15 | test.py:17 | s | exception.info | -| test.py:19:13:19:36 | test.py:19 | Attribute() | [exception.info] | -| test.py:20:13:20:37 | test.py:20 | Attribute() | [exception.info] | -| test.py:21:13:21:36 | test.py:21 | Attribute() | [exception.info] | -| test.py:21:35:21:35 | test.py:21 | t | [exception.info] | -| test.py:22:13:22:58 | test.py:22 | Attribute() | [exception.info] | -| test.py:23:13:23:57 | test.py:23 | Attribute() | [exception.info] | -| test.py:24:13:24:35 | test.py:24 | Attribute() | [exception.info] | -| test.py:25:13:25:36 | test.py:25 | Attribute() | [exception.info] | -| test.py:26:25:26:25 | test.py:26 | e | exception.kind | -| test.py:26:25:26:33 | test.py:26 | Attribute | exception.info | -| test.py:26:25:26:41 | test.py:26 | Tuple | [[exception.info]] | -| test.py:26:25:26:41 | test.py:26 | Tuple | [exception.info] | -| test.py:26:36:26:36 | test.py:26 | e | exception.kind | -| test.py:26:36:26:41 | test.py:26 | Attribute | [exception.info] | -| test.py:27:19:27:19 | test.py:27 | t | [exception.info] | -| test.py:27:22:27:22 | test.py:27 | u | [exception.info] | -| test.py:27:25:27:25 | test.py:27 | v | [exception.info] | -| test.py:27:28:27:28 | test.py:27 | w | [exception.info] | -| test.py:27:31:27:31 | test.py:27 | x | [exception.info] | -| test.py:27:34:27:34 | test.py:27 | y | [exception.info] | -| test.py:27:37:27:37 | test.py:27 | z | [exception.info] | -| test.py:27:40:27:46 | test.py:27 | message | exception.info | -| test.py:27:49:27:52 | test.py:27 | args | [exception.info] | diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestNode.ql b/python/ql/test/library-tests/taint/exception_traceback/TestNode.ql deleted file mode 100644 index f3c7e98de94..00000000000 --- a/python/ql/test/library-tests/taint/exception_traceback/TestNode.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.security.Exceptions -import semmle.python.web.HttpResponse - -from TaintedNode node -where not node.getLocation().getFile().inStdlib() -select node.getLocation(), node.getNode().asAstNode().toString(), node.getTaintKind() diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestSource.expected b/python/ql/test/library-tests/taint/exception_traceback/TestSource.expected deleted file mode 100644 index e8b2074bc28..00000000000 --- a/python/ql/test/library-tests/taint/exception_traceback/TestSource.expected +++ /dev/null @@ -1,10 +0,0 @@ -| test.py:10 | MyException() | exception.kind | -| test.py:15 | e | exception.kind | -| test.py:16 | Attribute() | exception.info | -| test.py:19 | Attribute() | [exception.info] | -| test.py:20 | Attribute() | [exception.info] | -| test.py:21 | Attribute() | [exception.info] | -| test.py:22 | Attribute() | [exception.info] | -| test.py:23 | Attribute() | [exception.info] | -| test.py:24 | Attribute() | [exception.info] | -| test.py:25 | Attribute() | [exception.info] | diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestSource.ql b/python/ql/test/library-tests/taint/exception_traceback/TestSource.ql deleted file mode 100644 index d892afe9999..00000000000 --- a/python/ql/test/library-tests/taint/exception_traceback/TestSource.ql +++ /dev/null @@ -1,9 +0,0 @@ -import python -import semmle.python.security.Exceptions -import semmle.python.web.HttpResponse - -from TaintSource src, TaintKind kind -where - src.isSourceOf(kind) and - not src.getLocation().getFile().inStdlib() -select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestStep.expected b/python/ql/test/library-tests/taint/exception_traceback/TestStep.expected deleted file mode 100644 index 196c1e92c2c..00000000000 --- a/python/ql/test/library-tests/taint/exception_traceback/TestStep.expected +++ /dev/null @@ -1,16 +0,0 @@ -| Taint [exception.info] | test.py:19 | Attribute() | | --> | Taint [exception.info] | test.py:21 | t | | -| Taint [exception.info] | test.py:19 | Attribute() | | --> | Taint [exception.info] | test.py:27 | t | | -| Taint [exception.info] | test.py:20 | Attribute() | | --> | Taint [exception.info] | test.py:27 | u | | -| Taint [exception.info] | test.py:21 | Attribute() | | --> | Taint [exception.info] | test.py:27 | v | | -| Taint [exception.info] | test.py:22 | Attribute() | | --> | Taint [exception.info] | test.py:27 | w | | -| Taint [exception.info] | test.py:23 | Attribute() | | --> | Taint [exception.info] | test.py:27 | x | | -| Taint [exception.info] | test.py:24 | Attribute() | | --> | Taint [exception.info] | test.py:27 | y | | -| Taint [exception.info] | test.py:25 | Attribute() | | --> | Taint [exception.info] | test.py:27 | z | | -| Taint [exception.info] | test.py:26 | Attribute | | --> | Taint [[exception.info]] | test.py:26 | Tuple | | -| Taint [exception.info] | test.py:26 | Attribute | | --> | Taint [exception.info] | test.py:27 | args | | -| Taint exception.info | test.py:16 | Attribute() | | --> | Taint exception.info | test.py:17 | s | | -| Taint exception.info | test.py:26 | Attribute | | --> | Taint [exception.info] | test.py:26 | Tuple | | -| Taint exception.info | test.py:26 | Attribute | | --> | Taint exception.info | test.py:27 | message | | -| Taint exception.kind | test.py:15 | e | | --> | Taint exception.kind | test.py:26 | e | | -| Taint exception.kind | test.py:26 | e | | --> | Taint [exception.info] | test.py:26 | Attribute | | -| Taint exception.kind | test.py:26 | e | | --> | Taint exception.info | test.py:26 | Attribute | | diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestStep.ql b/python/ql/test/library-tests/taint/exception_traceback/TestStep.ql deleted file mode 100644 index b1ab12d0f25..00000000000 --- a/python/ql/test/library-tests/taint/exception_traceback/TestStep.ql +++ /dev/null @@ -1,12 +0,0 @@ -import python -import semmle.python.security.Exceptions -import semmle.python.web.HttpResponse - -from TaintedNode n, TaintedNode s -where - s = n.getASuccessor() and - not n.getLocation().getFile().inStdlib() and - not s.getLocation().getFile().inStdlib() -select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getNode().toString(), - n.getContext(), " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), - s.getNode().toString(), s.getContext() diff --git a/python/ql/test/library-tests/taint/exception_traceback/test.py b/python/ql/test/library-tests/taint/exception_traceback/test.py deleted file mode 100644 index 20573aa8f8b..00000000000 --- a/python/ql/test/library-tests/taint/exception_traceback/test.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import print_function - -import traceback -import sys - -class MyException(Exception): - pass - -def raise_secret_exception(): - raise MyException("Message", "secret info") - -def foo(): - try: - raise_secret_exception() - except Exception as e: - s = traceback.format_exc() - print(s) - etype, evalue, tb = sys.exc_info() - t = traceback.extract_tb(tb) - u = traceback.extract_stack() - v = traceback.format_list(t) - w = traceback.format_exception_only(etype, evalue) - x = traceback.format_exception(etype, evalue, tb) - y = traceback.format_tb(tb) - z = traceback.format_stack() - message, args = e.message, e.args - print(tb, t, u, v, w, x, y, z, message, args) - - -foo() - - -#For test to find stdlib -import os diff --git a/python/ql/test/library-tests/taint/flowpath_regression/Config.qll b/python/ql/test/library-tests/taint/flowpath_regression/Config.qll deleted file mode 100644 index ae9d0e3c332..00000000000 --- a/python/ql/test/library-tests/taint/flowpath_regression/Config.qll +++ /dev/null @@ -1,45 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted - -class FooSource extends TaintSource { - FooSource() { this.(CallNode).getFunction().(NameNode).getId() = "foo_source" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof UntrustedStringKind } - - override string toString() { result = "FooSource" } -} - -class FooSink extends TaintSink { - FooSink() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "foo_sink" and - call.getAnArg() = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof UntrustedStringKind } - - override string toString() { result = "FooSink" } -} - -class FooConfig extends TaintTracking::Configuration { - FooConfig() { this = "FooConfig" } - - override predicate isSource(TaintTracking::Source source) { source instanceof FooSource } - - override predicate isSink(TaintTracking::Sink sink) { sink instanceof FooSink } -} - -class BarSink extends TaintSink { - BarSink() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "bar_sink" and - call.getAnArg() = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof UntrustedStringKind } - - override string toString() { result = "BarSink" } -} diff --git a/python/ql/test/library-tests/taint/flowpath_regression/Path.expected b/python/ql/test/library-tests/taint/flowpath_regression/Path.expected deleted file mode 100644 index b03f12e8b9a..00000000000 --- a/python/ql/test/library-tests/taint/flowpath_regression/Path.expected +++ /dev/null @@ -1 +0,0 @@ -| test.py:16:9:16:20 | foo_source() | test.py:17:14:17:14 | x | diff --git a/python/ql/test/library-tests/taint/flowpath_regression/Path.ql b/python/ql/test/library-tests/taint/flowpath_regression/Path.ql deleted file mode 100644 index 43562780859..00000000000 --- a/python/ql/test/library-tests/taint/flowpath_regression/Path.ql +++ /dev/null @@ -1,6 +0,0 @@ -import python -import Config - -from FooConfig config, TaintedPathSource src, TaintedPathSink sink -where config.hasFlowPath(src, sink) -select src.getSource(), sink.getSink() diff --git a/python/ql/test/library-tests/taint/flowpath_regression/test.py b/python/ql/test/library-tests/taint/flowpath_regression/test.py deleted file mode 100644 index 7287649330b..00000000000 --- a/python/ql/test/library-tests/taint/flowpath_regression/test.py +++ /dev/null @@ -1,22 +0,0 @@ -def foo_source(): - return 'foo' - - -def foo_sink(x): - if x == 'foo': - print('fire the foo missiles') - - -def bar_sink(x): - if x == 'bar': - print('fire the bar missiles') - - -def should_report(): - x = foo_source() - foo_sink(x) - - -def should_not_report(): - x = foo_source() - bar_sink(x) diff --git a/python/ql/test/library-tests/taint/namedtuple/SanitizedEdges.expected b/python/ql/test/library-tests/taint/namedtuple/SanitizedEdges.expected deleted file mode 100644 index 0adf64dfd5d..00000000000 --- a/python/ql/test/library-tests/taint/namedtuple/SanitizedEdges.expected +++ /dev/null @@ -1,7 +0,0 @@ -| UrlsplitUrlparseTempSanitizer | [externally controlled string] | test.py:21 | Pi(urlsplit_res_0) [true] | -| UrlsplitUrlparseTempSanitizer | [externally controlled string] | test.py:24 | Pi(urlsplit_res_3) [true] | -| UrlsplitUrlparseTempSanitizer | [externally controlled string] | test.py:27 | Pi(urlsplit_res_6) [true] | -| UrlsplitUrlparseTempSanitizer | [externally controlled string] | test.py:30 | Pi(urlsplit_res_9) [true] | -| string equality sanitizer | externally controlled string | test.py:21 | Pi(urlsplit_res_0) [true] | -| string equality sanitizer | externally controlled string | test.py:24 | Pi(urlsplit_res_3) [true] | -| string equality sanitizer | externally controlled string | test.py:27 | Pi(urlsplit_res_6) [true] | diff --git a/python/ql/test/library-tests/taint/namedtuple/SanitizedEdges.ql b/python/ql/test/library-tests/taint/namedtuple/SanitizedEdges.ql deleted file mode 100644 index d523f79a963..00000000000 --- a/python/ql/test/library-tests/taint/namedtuple/SanitizedEdges.ql +++ /dev/null @@ -1,6 +0,0 @@ -import python -import Taint - -from Sanitizer s, TaintKind taint, PyEdgeRefinement test -where s.sanitizingEdge(taint, test) -select s, taint, test.getTest().getLocation().toString(), test.getRepresentation() diff --git a/python/ql/test/library-tests/taint/namedtuple/Taint.qll b/python/ql/test/library-tests/taint/namedtuple/Taint.qll deleted file mode 100644 index 0dc3c71ec84..00000000000 --- a/python/ql/test/library-tests/taint/namedtuple/Taint.qll +++ /dev/null @@ -1,45 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted - -class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "taint source" } -} - -class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - - override string toString() { result = "list taint source" } -} - -class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - - override string toString() { result = "dict taint source" } -} - -class TestConfig extends TaintTracking::Configuration { - TestConfig() { this = "TestConfig" } - - override predicate isSanitizer(Sanitizer sanitizer) { - sanitizer instanceof UrlsplitUrlparseTempSanitizer - } - - override predicate isSource(TaintTracking::Source source) { - source instanceof SimpleSource - or - source instanceof ListSource - or - source instanceof DictSource - } - - override predicate isSink(TaintTracking::Sink sink) { none() } -} diff --git a/python/ql/test/library-tests/taint/namedtuple/TestTaint.expected b/python/ql/test/library-tests/taint/namedtuple/TestTaint.expected deleted file mode 100644 index 62b589299dd..00000000000 --- a/python/ql/test/library-tests/taint/namedtuple/TestTaint.expected +++ /dev/null @@ -1,15 +0,0 @@ -| test.py:13 | test_basic | a | externally controlled string | -| test.py:13 | test_basic | b | externally controlled string | -| test.py:13 | test_basic | c | externally controlled string | -| test.py:13 | test_basic | d | externally controlled string | -| test.py:13 | test_basic | urlsplit_res | [externally controlled string] | -| test.py:19 | test_sanitizer | Attribute | externally controlled string | -| test.py:22 | test_sanitizer | Attribute | NO TAINT | -| test.py:25 | test_sanitizer | Subscript | NO TAINT | -| test.py:28 | test_sanitizer | Attribute | NO TAINT | -| test.py:31 | test_sanitizer | Attribute | NO TAINT | -| test.py:34 | test_sanitizer | Attribute | externally controlled string | -| test.py:44 | test_namedtuple | a | NO TAINT | -| test.py:44 | test_namedtuple | b | NO TAINT | -| test.py:44 | test_namedtuple | c | NO TAINT | -| test.py:44 | test_namedtuple | d | NO TAINT | diff --git a/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql b/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql deleted file mode 100644 index 47883578516..00000000000 --- a/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql +++ /dev/null @@ -1,19 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import Taint - -from Call call, Expr arg, string taint_string -where - call.getLocation().getFile().getShortName() = "test.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) - ) -select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string diff --git a/python/ql/test/library-tests/taint/namedtuple/test.py b/python/ql/test/library-tests/taint/namedtuple/test.py deleted file mode 100644 index ec6304f5073..00000000000 --- a/python/ql/test/library-tests/taint/namedtuple/test.py +++ /dev/null @@ -1,44 +0,0 @@ -from six.moves.urllib.parse import urlsplit - -# Currently we don't have support for namedtuples in general, but do have special support -# for `urlsplit` (and `urlparse`) - -def test_basic(): - tainted_string = TAINTED_STRING - urlsplit_res = urlsplit(tainted_string) - a = urlsplit_res.netloc # field access - b = urlsplit_res.hostname # property - c = urlsplit_res[3] # indexing - _, _, d, _, _ = urlsplit(tainted_string) # unpacking - test(a, b, c, d, urlsplit_res) - -def test_sanitizer(): - tainted_string = TAINTED_STRING - urlsplit_res = urlsplit(tainted_string) - - test(urlsplit_res.netloc) # should be tainted - - if urlsplit_res.netloc == "OK": - test(urlsplit_res.netloc) - - if urlsplit_res[2] == "OK": - test(urlsplit_res[0]) - - if urlsplit_res.netloc == "OK": - test(urlsplit_res.path) # FN - - if urlsplit_res.netloc in ["OK"]: - test(urlsplit_res.netloc) - - if urlsplit_res.netloc in ["OK", non_constant()]: - test(urlsplit_res.netloc) # should be tainted - -def test_namedtuple(): - tainted_string = TAINTED_STRING - Point = namedtuple('Point', ['x', 'y']) - p = Point('safe', tainted_string) - a = p.x - b = p.y - c = p[0] - d = p[1] - test(a, b, c, d) # TODO: FN, at least p.y and p[1] should be tainted diff --git a/python/ql/test/library-tests/taint/strings/Taint.qll b/python/ql/test/library-tests/taint/strings/Taint.qll deleted file mode 100644 index 3368a1c4f70..00000000000 --- a/python/ql/test/library-tests/taint/strings/Taint.qll +++ /dev/null @@ -1,44 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted -import semmle.python.security.Exceptions - -class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "taint source" } -} - -class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - - override string toString() { result = "list taint source" } -} - -class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - - override string toString() { result = "dict taint source" } -} - -class ExceptionInfoSource extends TaintSource { - ExceptionInfoSource() { this.(NameNode).getId() = "TAINTED_EXCEPTION_INFO" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfo } - - override string toString() { result = "Exception info source" } -} - -class ExternalFileObjectSource extends TaintSource { - ExternalFileObjectSource() { this.(NameNode).getId() = "TAINTED_FILE" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalFileObject } - - override string toString() { result = "Tainted file source" } -} diff --git a/python/ql/test/library-tests/taint/strings/TestStep.expected b/python/ql/test/library-tests/taint/strings/TestStep.expected deleted file mode 100644 index 4dc6682ee81..00000000000 --- a/python/ql/test/library-tests/taint/strings/TestStep.expected +++ /dev/null @@ -1,162 +0,0 @@ -| Taint [[externally controlled string]] | test.py:74 | test.py:74:9:74:33 | parse_qsl() | | --> | Taint [[externally controlled string]] | test.py:75 | test.py:75:19:75:19 | d | | -| Taint [externally controlled string] | test.py:71 | test.py:71:9:71:32 | urlsplit() | | --> | Taint [externally controlled string] | test.py:75 | test.py:75:10:75:10 | a | | -| Taint [externally controlled string] | test.py:72 | test.py:72:9:72:32 | urlparse() | | --> | Taint [externally controlled string] | test.py:75 | test.py:75:13:75:13 | b | | -| Taint [externally controlled string] | test.py:104 | test.py:104:9:104:37 | Attribute() | | --> | Taint externally controlled string | test.py:104 | test.py:104:9:104:40 | Subscript | | -| Taint [externally controlled string] | test.py:108 | test.py:108:9:108:38 | Attribute() | | --> | Taint externally controlled string | test.py:108 | test.py:108:9:108:41 | Subscript | | -| Taint [externally controlled string] | test.py:110 | test.py:110:9:110:37 | Attribute() | | --> | Taint externally controlled string | test.py:110 | test.py:110:9:110:41 | Subscript | | -| Taint [externally controlled string] | test.py:113 | test.py:113:9:113:30 | Attribute() | | --> | Taint externally controlled string | test.py:113 | test.py:113:9:113:33 | Subscript | | -| Taint [externally controlled string] | test.py:115 | test.py:115:9:115:35 | Attribute() | | --> | Taint externally controlled string | test.py:115 | test.py:115:9:115:38 | Subscript | | -| Taint exception.info | test.py:45 | test.py:45:22:45:26 | taint | p1 = exception.info | --> | Taint exception.info | test.py:46 | test.py:46:17:46:21 | taint | p1 = exception.info | -| Taint exception.info | test.py:46 | test.py:46:17:46:21 | taint | p1 = exception.info | --> | Taint exception.info | test.py:46 | test.py:46:12:46:22 | func() | p1 = exception.info | -| Taint exception.info | test.py:46 | test.py:46:17:46:21 | taint | p1 = exception.info | --> | Taint exception.info | test.py:53 | test.py:53:19:53:21 | arg | p0 = exception.info | -| Taint exception.info | test.py:49 | test.py:49:12:49:33 | TAINTED_EXCEPTION_INFO | | --> | Taint exception.info | test.py:50 | test.py:50:37:50:40 | info | | -| Taint exception.info | test.py:50 | test.py:50:11:50:41 | cross_over() | | --> | Taint exception.info | test.py:51 | test.py:51:10:51:12 | res | | -| Taint exception.info | test.py:50 | test.py:50:37:50:40 | info | | --> | Taint exception.info | test.py:45 | test.py:45:22:45:26 | taint | p1 = exception.info | -| Taint exception.info | test.py:50 | test.py:50:37:50:40 | info | | --> | Taint exception.info | test.py:50 | test.py:50:11:50:41 | cross_over() | | -| Taint exception.info | test.py:53 | test.py:53:19:53:21 | arg | p0 = exception.info | --> | Taint exception.info | test.py:54 | test.py:54:12:54:14 | arg | p0 = exception.info | -| Taint externally controlled string | test.py:6 | test.py:6:22:6:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:7 | test.py:7:31:7:44 | tainted_string | | -| Taint externally controlled string | test.py:7 | test.py:7:31:7:44 | tainted_string | | --> | Taint json[externally controlled string] | test.py:7 | test.py:7:20:7:45 | Attribute() | | -| Taint externally controlled string | test.py:8 | test.py:8:9:8:25 | Subscript | | --> | Taint externally controlled string | test.py:9 | test.py:9:9:9:9 | a | | -| Taint externally controlled string | test.py:8 | test.py:8:9:8:25 | Subscript | | --> | Taint externally controlled string | test.py:11 | test.py:11:10:11:10 | a | | -| Taint externally controlled string | test.py:9 | test.py:9:9:9:18 | Attribute() | | --> | Taint externally controlled string | test.py:10 | test.py:10:9:10:9 | b | | -| Taint externally controlled string | test.py:9 | test.py:9:9:9:18 | Attribute() | | --> | Taint externally controlled string | test.py:11 | test.py:11:13:11:13 | b | | -| Taint externally controlled string | test.py:10 | test.py:10:9:10:14 | Subscript | | --> | Taint externally controlled string | test.py:11 | test.py:11:16:11:16 | c | | -| Taint externally controlled string | test.py:14 | test.py:14:22:14:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:15 | test.py:15:9:15:22 | tainted_string | | -| Taint externally controlled string | test.py:14 | test.py:14:22:14:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:16 | test.py:16:9:16:22 | tainted_string | | -| Taint externally controlled string | test.py:14 | test.py:14:22:14:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:17 | test.py:17:9:17:22 | tainted_string | | -| Taint externally controlled string | test.py:14 | test.py:14:22:14:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:18 | test.py:18:9:18:22 | tainted_string | | -| Taint externally controlled string | test.py:14 | test.py:14:22:14:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:19 | test.py:19:18:19:31 | tainted_string | | -| Taint externally controlled string | test.py:14 | test.py:14:22:14:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:20 | test.py:20:14:20:27 | tainted_string | | -| Taint externally controlled string | test.py:14 | test.py:14:22:14:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:21 | test.py:21:9:21:22 | tainted_string | | -| Taint externally controlled string | test.py:15 | test.py:15:9:15:22 | tainted_string | | --> | Taint externally controlled string | test.py:15 | test.py:15:9:15:31 | Attribute() | | -| Taint externally controlled string | test.py:15 | test.py:15:9:15:31 | Attribute() | | --> | Taint externally controlled string | test.py:22 | test.py:22:10:22:10 | a | | -| Taint externally controlled string | test.py:16 | test.py:16:9:16:22 | tainted_string | | --> | Taint externally controlled string | test.py:16 | test.py:16:9:16:29 | Attribute() | | -| Taint externally controlled string | test.py:16 | test.py:16:9:16:29 | Attribute() | | --> | Taint externally controlled string | test.py:22 | test.py:22:13:22:13 | b | | -| Taint externally controlled string | test.py:17 | test.py:17:9:17:22 | tainted_string | | --> | Taint externally controlled string | test.py:17 | test.py:17:9:17:25 | Subscript | | -| Taint externally controlled string | test.py:17 | test.py:17:9:17:25 | Subscript | | --> | Taint externally controlled string | test.py:22 | test.py:22:16:22:16 | c | | -| Taint externally controlled string | test.py:18 | test.py:18:9:18:22 | tainted_string | | --> | Taint externally controlled string | test.py:18 | test.py:18:9:18:27 | Subscript | | -| Taint externally controlled string | test.py:18 | test.py:18:9:18:27 | Subscript | | --> | Taint externally controlled string | test.py:22 | test.py:22:19:22:19 | d | | -| Taint externally controlled string | test.py:19 | test.py:19:9:19:32 | reversed() | | --> | Taint externally controlled string | test.py:22 | test.py:22:22:22:22 | e | | -| Taint externally controlled string | test.py:19 | test.py:19:18:19:31 | tainted_string | | --> | Taint externally controlled string | test.py:19 | test.py:19:9:19:32 | reversed() | | -| Taint externally controlled string | test.py:20 | test.py:20:9:20:28 | copy() | | --> | Taint externally controlled string | test.py:22 | test.py:22:25:22:25 | f | | -| Taint externally controlled string | test.py:20 | test.py:20:14:20:27 | tainted_string | | --> | Taint externally controlled string | test.py:20 | test.py:20:9:20:28 | copy() | | -| Taint externally controlled string | test.py:21 | test.py:21:9:21:22 | tainted_string | | --> | Taint externally controlled string | test.py:21 | test.py:21:9:21:30 | Attribute() | | -| Taint externally controlled string | test.py:21 | test.py:21:9:21:30 | Attribute() | | --> | Taint externally controlled string | test.py:22 | test.py:22:28:22:28 | g | | -| Taint externally controlled string | test.py:25 | test.py:25:22:25:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:26 | test.py:26:8:26:21 | tainted_string | | -| Taint externally controlled string | test.py:25 | test.py:25:22:25:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:29 | test.py:29:14:29:27 | tainted_string | | -| Taint externally controlled string | test.py:32 | test.py:32:22:32:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:33 | test.py:33:8:33:21 | tainted_string | | -| Taint externally controlled string | test.py:32 | test.py:32:22:32:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:33 | test.py:33:34:33:47 | tainted_string | | -| Taint externally controlled string | test.py:32 | test.py:32:22:32:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:36 | test.py:36:14:36:27 | tainted_string | | -| Taint externally controlled string | test.py:39 | test.py:39:22:39:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:40 | test.py:40:13:40:26 | tainted_string | | -| Taint externally controlled string | test.py:39 | test.py:39:22:39:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:41 | test.py:41:15:41:28 | tainted_string | | -| Taint externally controlled string | test.py:39 | test.py:39:22:39:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:42 | test.py:42:15:42:28 | tainted_string | | -| Taint externally controlled string | test.py:40 | test.py:40:9:40:27 | str() | | --> | Taint externally controlled string | test.py:43 | test.py:43:10:43:10 | a | | -| Taint externally controlled string | test.py:40 | test.py:40:13:40:26 | tainted_string | | --> | Taint externally controlled string | test.py:40 | test.py:40:9:40:27 | str() | | -| Taint externally controlled string | test.py:41 | test.py:41:9:41:29 | bytes() | | --> | Taint externally controlled string | test.py:43 | test.py:43:13:43:13 | b | | -| Taint externally controlled string | test.py:41 | test.py:41:15:41:28 | tainted_string | | --> | Taint externally controlled string | test.py:41 | test.py:41:9:41:29 | bytes() | | -| Taint externally controlled string | test.py:42 | test.py:42:9:42:46 | bytes() | | --> | Taint externally controlled string | test.py:43 | test.py:43:16:43:16 | c | | -| Taint externally controlled string | test.py:42 | test.py:42:15:42:28 | tainted_string | | --> | Taint externally controlled string | test.py:42 | test.py:42:9:42:46 | bytes() | | -| Taint externally controlled string | test.py:45 | test.py:45:22:45:26 | taint | p1 = externally controlled string | --> | Taint externally controlled string | test.py:46 | test.py:46:17:46:21 | taint | p1 = externally controlled string | -| Taint externally controlled string | test.py:46 | test.py:46:17:46:21 | taint | p1 = externally controlled string | --> | Taint externally controlled string | test.py:46 | test.py:46:12:46:22 | func() | p1 = externally controlled string | -| Taint externally controlled string | test.py:46 | test.py:46:17:46:21 | taint | p1 = externally controlled string | --> | Taint externally controlled string | test.py:53 | test.py:53:19:53:21 | arg | p0 = externally controlled string | -| Taint externally controlled string | test.py:53 | test.py:53:19:53:21 | arg | p0 = externally controlled string | --> | Taint externally controlled string | test.py:54 | test.py:54:12:54:14 | arg | p0 = externally controlled string | -| Taint externally controlled string | test.py:57 | test.py:57:11:57:24 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:58 | test.py:58:38:58:40 | ext | | -| Taint externally controlled string | test.py:58 | test.py:58:11:58:41 | cross_over() | | --> | Taint externally controlled string | test.py:59 | test.py:59:10:59:12 | res | | -| Taint externally controlled string | test.py:58 | test.py:58:38:58:40 | ext | | --> | Taint externally controlled string | test.py:45 | test.py:45:22:45:26 | taint | p1 = externally controlled string | -| Taint externally controlled string | test.py:58 | test.py:58:38:58:40 | ext | | --> | Taint externally controlled string | test.py:58 | test.py:58:11:58:41 | cross_over() | | -| Taint externally controlled string | test.py:70 | test.py:70:22:70:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:71 | test.py:71:18:71:31 | tainted_string | | -| Taint externally controlled string | test.py:70 | test.py:70:22:70:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:72 | test.py:72:18:72:31 | tainted_string | | -| Taint externally controlled string | test.py:70 | test.py:70:22:70:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:73 | test.py:73:18:73:31 | tainted_string | | -| Taint externally controlled string | test.py:70 | test.py:70:22:70:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:74 | test.py:74:19:74:32 | tainted_string | | -| Taint externally controlled string | test.py:71 | test.py:71:18:71:31 | tainted_string | | --> | Taint [externally controlled string] | test.py:71 | test.py:71:9:71:32 | urlsplit() | | -| Taint externally controlled string | test.py:72 | test.py:72:18:72:31 | tainted_string | | --> | Taint [externally controlled string] | test.py:72 | test.py:72:9:72:32 | urlparse() | | -| Taint externally controlled string | test.py:73 | test.py:73:18:73:31 | tainted_string | | --> | Taint {externally controlled string} | test.py:73 | test.py:73:9:73:32 | parse_qs() | | -| Taint externally controlled string | test.py:74 | test.py:74:19:74:32 | tainted_string | | --> | Taint [[externally controlled string]] | test.py:74 | test.py:74:9:74:33 | parse_qsl() | | -| Taint externally controlled string | test.py:78 | test.py:78:22:78:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:80 | test.py:80:9:80:22 | tainted_string | | -| Taint externally controlled string | test.py:78 | test.py:78:22:78:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:82 | test.py:82:12:82:25 | tainted_string | | -| Taint externally controlled string | test.py:80 | test.py:80:9:80:22 | tainted_string | | --> | Taint externally controlled string | test.py:80 | test.py:80:9:80:30 | Attribute() | | -| Taint externally controlled string | test.py:80 | test.py:80:9:80:30 | Attribute() | | --> | Taint externally controlled string | test.py:85 | test.py:85:10:85:10 | a | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:91 | test.py:91:9:91:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:92 | test.py:92:9:92:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:93 | test.py:93:9:93:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:94 | test.py:94:9:94:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:95 | test.py:95:9:95:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:96 | test.py:96:9:96:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:97 | test.py:97:9:97:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:98 | test.py:98:9:98:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:99 | test.py:99:9:99:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:100 | test.py:100:9:100:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:101 | test.py:101:9:101:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:102 | test.py:102:9:102:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:103 | test.py:103:9:103:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:104 | test.py:104:9:104:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:105 | test.py:105:9:105:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:106 | test.py:106:9:106:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:107 | test.py:107:9:107:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:108 | test.py:108:9:108:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:109 | test.py:109:9:109:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:110 | test.py:110:9:110:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:111 | test.py:111:9:111:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:112 | test.py:112:9:112:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:113 | test.py:113:9:113:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:114 | test.py:114:9:114:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:115 | test.py:115:9:115:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:116 | test.py:116:9:116:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:117 | test.py:117:9:117:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:118 | test.py:118:9:118:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:121 | test.py:121:9:121:22 | tainted_string | | -| Taint externally controlled string | test.py:88 | test.py:88:22:88:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:122 | test.py:122:9:122:22 | tainted_string | | -| Taint externally controlled string | test.py:91 | test.py:91:9:91:22 | tainted_string | | --> | Taint externally controlled string | test.py:91 | test.py:91:9:91:35 | Attribute() | | -| Taint externally controlled string | test.py:92 | test.py:92:9:92:22 | tainted_string | | --> | Taint externally controlled string | test.py:92 | test.py:92:9:92:33 | Attribute() | | -| Taint externally controlled string | test.py:93 | test.py:93:9:93:22 | tainted_string | | --> | Taint externally controlled string | test.py:93 | test.py:93:9:93:31 | Attribute() | | -| Taint externally controlled string | test.py:94 | test.py:94:9:94:22 | tainted_string | | --> | Taint externally controlled string | test.py:94 | test.py:94:9:94:38 | Attribute() | | -| Taint externally controlled string | test.py:95 | test.py:95:9:95:22 | tainted_string | | --> | Taint externally controlled string | test.py:95 | test.py:95:9:95:38 | Attribute() | | -| Taint externally controlled string | test.py:95 | test.py:95:9:95:38 | Attribute() | | --> | Taint externally controlled string | test.py:95 | test.py:95:9:95:54 | Attribute() | | -| Taint externally controlled string | test.py:96 | test.py:96:9:96:22 | tainted_string | | --> | Taint externally controlled string | test.py:96 | test.py:96:9:96:35 | Attribute() | | -| Taint externally controlled string | test.py:97 | test.py:97:9:97:22 | tainted_string | | --> | Taint externally controlled string | test.py:97 | test.py:97:9:97:37 | Attribute() | | -| Taint externally controlled string | test.py:98 | test.py:98:9:98:22 | tainted_string | | --> | Taint externally controlled string | test.py:98 | test.py:98:9:98:46 | Attribute() | | -| Taint externally controlled string | test.py:99 | test.py:99:9:99:22 | tainted_string | | --> | Taint externally controlled string | test.py:99 | test.py:99:9:99:33 | Attribute() | | -| Taint externally controlled string | test.py:100 | test.py:100:9:100:22 | tainted_string | | --> | Taint externally controlled string | test.py:100 | test.py:100:9:100:30 | Attribute() | | -| Taint externally controlled string | test.py:101 | test.py:101:9:101:22 | tainted_string | | --> | Taint externally controlled string | test.py:101 | test.py:101:9:101:31 | Attribute() | | -| Taint externally controlled string | test.py:102 | test.py:102:9:102:22 | tainted_string | | --> | Taint externally controlled string | test.py:102 | test.py:102:9:102:35 | Attribute() | | -| Taint externally controlled string | test.py:103 | test.py:103:9:103:22 | tainted_string | | --> | Taint [externally controlled string] | test.py:103 | test.py:103:9:103:37 | Attribute() | | -| Taint externally controlled string | test.py:104 | test.py:104:9:104:22 | tainted_string | | --> | Taint [externally controlled string] | test.py:104 | test.py:104:9:104:37 | Attribute() | | -| Taint externally controlled string | test.py:105 | test.py:105:9:105:22 | tainted_string | | --> | Taint externally controlled string | test.py:105 | test.py:105:9:105:42 | Attribute() | | -| Taint externally controlled string | test.py:106 | test.py:106:9:106:22 | tainted_string | | --> | Taint externally controlled string | test.py:106 | test.py:106:9:106:33 | Attribute() | | -| Taint externally controlled string | test.py:107 | test.py:107:9:107:22 | tainted_string | | --> | Taint [externally controlled string] | test.py:107 | test.py:107:9:107:38 | Attribute() | | -| Taint externally controlled string | test.py:108 | test.py:108:9:108:22 | tainted_string | | --> | Taint [externally controlled string] | test.py:108 | test.py:108:9:108:38 | Attribute() | | -| Taint externally controlled string | test.py:109 | test.py:109:9:109:22 | tainted_string | | --> | Taint [externally controlled string] | test.py:109 | test.py:109:9:109:37 | Attribute() | | -| Taint externally controlled string | test.py:110 | test.py:110:9:110:22 | tainted_string | | --> | Taint [externally controlled string] | test.py:110 | test.py:110:9:110:37 | Attribute() | | -| Taint externally controlled string | test.py:111 | test.py:111:9:111:22 | tainted_string | | --> | Taint externally controlled string | test.py:111 | test.py:111:9:111:31 | Attribute() | | -| Taint externally controlled string | test.py:112 | test.py:112:9:112:22 | tainted_string | | --> | Taint [externally controlled string] | test.py:112 | test.py:112:9:112:30 | Attribute() | | -| Taint externally controlled string | test.py:113 | test.py:113:9:113:22 | tainted_string | | --> | Taint [externally controlled string] | test.py:113 | test.py:113:9:113:30 | Attribute() | | -| Taint externally controlled string | test.py:114 | test.py:114:9:114:22 | tainted_string | | --> | Taint [externally controlled string] | test.py:114 | test.py:114:9:114:35 | Attribute() | | -| Taint externally controlled string | test.py:115 | test.py:115:9:115:22 | tainted_string | | --> | Taint [externally controlled string] | test.py:115 | test.py:115:9:115:35 | Attribute() | | -| Taint externally controlled string | test.py:116 | test.py:116:9:116:22 | tainted_string | | --> | Taint externally controlled string | test.py:116 | test.py:116:9:116:30 | Attribute() | | -| Taint externally controlled string | test.py:117 | test.py:117:9:117:22 | tainted_string | | --> | Taint externally controlled string | test.py:117 | test.py:117:9:117:33 | Attribute() | | -| Taint externally controlled string | test.py:118 | test.py:118:9:118:22 | tainted_string | | --> | Taint externally controlled string | test.py:118 | test.py:118:9:118:30 | Attribute() | | -| Taint externally controlled string | test.py:121 | test.py:121:9:121:22 | tainted_string | | --> | Taint externally controlled string | test.py:121 | test.py:121:9:121:30 | Attribute() | | -| Taint externally controlled string | test.py:122 | test.py:122:9:122:22 | tainted_string | | --> | Taint externally controlled string | test.py:122 | test.py:122:9:122:33 | Attribute() | | -| Taint externally controlled string | test.py:133 | test.py:133:5:133:29 | For | | --> | Taint externally controlled string | test.py:134 | test.py:134:14:134:17 | line | | -| Taint file[externally controlled string] | test.py:126 | test.py:126:20:126:31 | TAINTED_FILE | | --> | Taint file[externally controlled string] | test.py:128 | test.py:128:9:128:20 | tainted_file | | -| Taint file[externally controlled string] | test.py:126 | test.py:126:20:126:31 | TAINTED_FILE | | --> | Taint file[externally controlled string] | test.py:129 | test.py:129:9:129:20 | tainted_file | | -| Taint file[externally controlled string] | test.py:126 | test.py:126:20:126:31 | TAINTED_FILE | | --> | Taint file[externally controlled string] | test.py:130 | test.py:130:9:130:20 | tainted_file | | -| Taint file[externally controlled string] | test.py:126 | test.py:126:20:126:31 | TAINTED_FILE | | --> | Taint file[externally controlled string] | test.py:131 | test.py:131:9:131:20 | tainted_file | | -| Taint file[externally controlled string] | test.py:126 | test.py:126:20:126:31 | TAINTED_FILE | | --> | Taint file[externally controlled string] | test.py:133 | test.py:133:17:133:28 | tainted_file | | -| Taint file[externally controlled string] | test.py:129 | test.py:129:9:129:20 | tainted_file | | --> | Taint externally controlled string | test.py:129 | test.py:129:9:129:27 | Attribute() | | -| Taint file[externally controlled string] | test.py:130 | test.py:130:9:130:20 | tainted_file | | --> | Taint externally controlled string | test.py:130 | test.py:130:9:130:31 | Attribute() | | -| Taint file[externally controlled string] | test.py:131 | test.py:131:9:131:20 | tainted_file | | --> | Taint [externally controlled string] | test.py:131 | test.py:131:9:131:32 | Attribute() | | -| Taint file[externally controlled string] | test.py:133 | test.py:133:17:133:28 | tainted_file | | --> | Taint externally controlled string | test.py:133 | test.py:133:5:133:29 | For | | -| Taint json[externally controlled string] | test.py:7 | test.py:7:20:7:45 | Attribute() | | --> | Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:20 | tainted_json | | -| Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:20 | tainted_json | | --> | Taint externally controlled string | test.py:8 | test.py:8:9:8:25 | Subscript | | -| Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:20 | tainted_json | | --> | Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:25 | Subscript | | -| Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:25 | Subscript | | --> | Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:9 | a | | -| Taint json[externally controlled string] | test.py:8 | test.py:8:9:8:25 | Subscript | | --> | Taint json[externally controlled string] | test.py:11 | test.py:11:10:11:10 | a | | -| Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:9 | a | | --> | Taint externally controlled string | test.py:9 | test.py:9:9:9:18 | Attribute() | | -| Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:9 | a | | --> | Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:18 | Attribute() | | -| Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:18 | Attribute() | | --> | Taint json[externally controlled string] | test.py:10 | test.py:10:9:10:9 | b | | -| Taint json[externally controlled string] | test.py:9 | test.py:9:9:9:18 | Attribute() | | --> | Taint json[externally controlled string] | test.py:11 | test.py:11:13:11:13 | b | | -| Taint json[externally controlled string] | test.py:10 | test.py:10:9:10:9 | b | | --> | Taint externally controlled string | test.py:10 | test.py:10:9:10:14 | Subscript | | -| Taint json[externally controlled string] | test.py:10 | test.py:10:9:10:9 | b | | --> | Taint json[externally controlled string] | test.py:10 | test.py:10:9:10:14 | Subscript | | -| Taint json[externally controlled string] | test.py:10 | test.py:10:9:10:14 | Subscript | | --> | Taint json[externally controlled string] | test.py:11 | test.py:11:16:11:16 | c | | -| Taint {externally controlled string} | test.py:73 | test.py:73:9:73:32 | parse_qs() | | --> | Taint {externally controlled string} | test.py:75 | test.py:75:16:75:16 | c | | diff --git a/python/ql/test/library-tests/taint/strings/TestStep.ql b/python/ql/test/library-tests/taint/strings/TestStep.ql deleted file mode 100644 index 177edce3498..00000000000 --- a/python/ql/test/library-tests/taint/strings/TestStep.ql +++ /dev/null @@ -1,11 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import Taint - -from TaintedNode n, TaintedNode s -where - n.getLocation().getFile().getShortName() = "test.py" and - s.getLocation().getFile().getShortName() = "test.py" and - s = n.getASuccessor() -select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getAstNode(), n.getContext(), - " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), s.getAstNode(), s.getContext() diff --git a/python/ql/test/library-tests/taint/strings/TestTaint.expected b/python/ql/test/library-tests/taint/strings/TestTaint.expected deleted file mode 100644 index afc30f98899..00000000000 --- a/python/ql/test/library-tests/taint/strings/TestTaint.expected +++ /dev/null @@ -1,63 +0,0 @@ -| test.py:11 | test_json | a | externally controlled string | -| test.py:11 | test_json | a | json[externally controlled string] | -| test.py:11 | test_json | b | externally controlled string | -| test.py:11 | test_json | b | json[externally controlled string] | -| test.py:11 | test_json | c | externally controlled string | -| test.py:11 | test_json | c | json[externally controlled string] | -| test.py:22 | test_str | a | externally controlled string | -| test.py:22 | test_str | b | externally controlled string | -| test.py:22 | test_str | c | externally controlled string | -| test.py:22 | test_str | d | externally controlled string | -| test.py:22 | test_str | e | externally controlled string | -| test.py:22 | test_str | f | externally controlled string | -| test.py:22 | test_str | g | externally controlled string | -| test.py:27 | test_const_sanitizer1 | tainted_string | NO TAINT | -| test.py:29 | test_const_sanitizer1 | tainted_string | externally controlled string | -| test.py:34 | test_const_sanitizer2 | tainted_string | NO TAINT | -| test.py:36 | test_const_sanitizer2 | tainted_string | externally controlled string | -| test.py:43 | test_str2 | a | externally controlled string | -| test.py:43 | test_str2 | b | externally controlled string | -| test.py:43 | test_str2 | c | externally controlled string | -| test.py:51 | test_exc_info | res | exception.info | -| test.py:59 | test_untrusted | res | externally controlled string | -| test.py:75 | test_urlsplit_urlparse | a | [externally controlled string] | -| test.py:75 | test_urlsplit_urlparse | b | [externally controlled string] | -| test.py:75 | test_urlsplit_urlparse | c | {externally controlled string} | -| test.py:75 | test_urlsplit_urlparse | d | [[externally controlled string]] | -| test.py:85 | test_method_reference | a | externally controlled string | -| test.py:85 | test_method_reference | b | NO TAINT | -| test.py:91 | test_str_methods | Attribute() | externally controlled string | -| test.py:92 | test_str_methods | Attribute() | externally controlled string | -| test.py:93 | test_str_methods | Attribute() | externally controlled string | -| test.py:94 | test_str_methods | Attribute() | externally controlled string | -| test.py:95 | test_str_methods | Attribute() | externally controlled string | -| test.py:96 | test_str_methods | Attribute() | externally controlled string | -| test.py:97 | test_str_methods | Attribute() | externally controlled string | -| test.py:98 | test_str_methods | Attribute() | externally controlled string | -| test.py:99 | test_str_methods | Attribute() | externally controlled string | -| test.py:100 | test_str_methods | Attribute() | externally controlled string | -| test.py:101 | test_str_methods | Attribute() | externally controlled string | -| test.py:102 | test_str_methods | Attribute() | externally controlled string | -| test.py:103 | test_str_methods | Attribute() | [externally controlled string] | -| test.py:104 | test_str_methods | Subscript | externally controlled string | -| test.py:105 | test_str_methods | Attribute() | externally controlled string | -| test.py:106 | test_str_methods | Attribute() | externally controlled string | -| test.py:107 | test_str_methods | Attribute() | [externally controlled string] | -| test.py:108 | test_str_methods | Subscript | externally controlled string | -| test.py:109 | test_str_methods | Attribute() | [externally controlled string] | -| test.py:110 | test_str_methods | Subscript | externally controlled string | -| test.py:111 | test_str_methods | Attribute() | externally controlled string | -| test.py:112 | test_str_methods | Attribute() | [externally controlled string] | -| test.py:113 | test_str_methods | Subscript | externally controlled string | -| test.py:114 | test_str_methods | Attribute() | [externally controlled string] | -| test.py:115 | test_str_methods | Subscript | externally controlled string | -| test.py:116 | test_str_methods | Attribute() | externally controlled string | -| test.py:117 | test_str_methods | Attribute() | externally controlled string | -| test.py:118 | test_str_methods | Attribute() | externally controlled string | -| test.py:121 | test_str_methods | Attribute() | externally controlled string | -| test.py:122 | test_str_methods | Attribute() | externally controlled string | -| test.py:128 | test_tainted_file | tainted_file | file[externally controlled string] | -| test.py:129 | test_tainted_file | Attribute() | externally controlled string | -| test.py:130 | test_tainted_file | Attribute() | externally controlled string | -| test.py:131 | test_tainted_file | Attribute() | [externally controlled string] | -| test.py:134 | test_tainted_file | line | externally controlled string | diff --git a/python/ql/test/library-tests/taint/strings/TestTaint.ql b/python/ql/test/library-tests/taint/strings/TestTaint.ql deleted file mode 100644 index 47883578516..00000000000 --- a/python/ql/test/library-tests/taint/strings/TestTaint.ql +++ /dev/null @@ -1,19 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import Taint - -from Call call, Expr arg, string taint_string -where - call.getLocation().getFile().getShortName() = "test.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) - ) -select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string diff --git a/python/ql/test/library-tests/taint/strings/test.py b/python/ql/test/library-tests/taint/strings/test.py deleted file mode 100644 index 78a0712ceca..00000000000 --- a/python/ql/test/library-tests/taint/strings/test.py +++ /dev/null @@ -1,134 +0,0 @@ -import json -from copy import copy -import sys - -def test_json(): - tainted_string = TAINTED_STRING - tainted_json = json.loads(tainted_string) - a = tainted_json["x"] - b = a.get("y") - c = b["z"] - test(a, b, c) - -def test_str(): - tainted_string = TAINTED_STRING - a = tainted_string.ljust(8) - b = tainted_string.copy() - c = tainted_string[:] - d = tainted_string[::2] - e = reversed(tainted_string) - f = copy(tainted_string) - g = tainted_string.strip() - test(a, b, c, d, e, f, g) - -def test_const_sanitizer1(): - tainted_string = TAINTED_STRING - if tainted_string == "OK": - test(tainted_string) # not tainted - else: - test(tainted_string) # still tainted - -def test_const_sanitizer2(): - tainted_string = TAINTED_STRING - if tainted_string == "OK" or tainted_string == "ALSO_OK": - test(tainted_string) # not tainted - else: - test(tainted_string) # still tainted - -def test_str2(): - tainted_string = TAINTED_STRING - a = str(tainted_string) - b = bytes(tainted_string) # This is an error in Python 3 - c = bytes(tainted_string, encoding="utf8") # This is an error in Python 2 - test(a, b, c) - -def cross_over(func, taint): - return func(taint) - -def test_exc_info(): - info = TAINTED_EXCEPTION_INFO - res = cross_over(exc_info_call, info) - test(res) - -def exc_info_call(arg): - return arg - -def test_untrusted(): - ext = TAINTED_STRING - res = cross_over(untrusted_call, ext) - test(res) - -def exc_untrusted_call(arg): - return arg - -if sys.version_info[0] == 2: - from urlparse import urlsplit, urlparse, parse_qs, parse_qsl -if sys.version_info[0] == 3: - from urllib.parse import urlsplit, urlparse, parse_qs, parse_qsl - -def test_urlsplit_urlparse(): - tainted_string = TAINTED_STRING - a = urlsplit(tainted_string) - b = urlparse(tainted_string) - c = parse_qs(tainted_string) - d = parse_qsl(tainted_string) - test(a, b, c, d) - -def test_method_reference(): - tainted_string = TAINTED_STRING - - a = tainted_string.title() - - func = tainted_string.title - b = func() - - test(a, b) # TODO: `b` not tainted - -def test_str_methods(): - tainted_string = TAINTED_STRING - - test( - tainted_string.capitalize(), - tainted_string.casefold(), - tainted_string.center(), - tainted_string.encode('utf-8'), - tainted_string.encode('utf-8').decode('utf-8'), - tainted_string.expandtabs(), - tainted_string.format(foo=42), - tainted_string.format_map({'foo': 42}), - tainted_string.ljust(100), - tainted_string.lower(), - tainted_string.lstrip(), - tainted_string.lstrip('w.'), - tainted_string.partition(';'), - tainted_string.partition(';')[0], - tainted_string.replace('/', '', 1), - tainted_string.rjust(100), - tainted_string.rpartition(';'), - tainted_string.rpartition(';')[2], - tainted_string.rsplit(';', 4), - tainted_string.rsplit(';', 4)[-1], - tainted_string.rstrip(), - tainted_string.split(), - tainted_string.split()[0], - tainted_string.splitlines(), - tainted_string.splitlines()[0], - tainted_string.strip(), - tainted_string.swapcase(), - tainted_string.title(), - # ignoring, as I have never seen this in practice - # tainted_string.translate(translation_table), - tainted_string.upper(), - tainted_string.zfill(100), - ) - -def test_tainted_file(): - tainted_file = TAINTED_FILE - test( - tainted_file, - tainted_file.read(), - tainted_file.readline(), - tainted_file.readlines(), - ) - for line in tainted_file: - test(line) diff --git a/python/ql/test/library-tests/taint/unpacking/Taint.qll b/python/ql/test/library-tests/taint/unpacking/Taint.qll deleted file mode 100644 index 010b9738c5c..00000000000 --- a/python/ql/test/library-tests/taint/unpacking/Taint.qll +++ /dev/null @@ -1,27 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted - -class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - - override string toString() { result = "taint source" } -} - -class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - - override string toString() { result = "list taint source" } -} - -class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - - override string toString() { result = "dict taint source" } -} diff --git a/python/ql/test/library-tests/taint/unpacking/TestStep.expected b/python/ql/test/library-tests/taint/unpacking/TestStep.expected deleted file mode 100644 index 5d800e6b5b8..00000000000 --- a/python/ql/test/library-tests/taint/unpacking/TestStep.expected +++ /dev/null @@ -1,41 +0,0 @@ -| Taint [[externally controlled string]] | test.py:19 | test.py:19:10:19:18 | List | | --> | Taint [[externally controlled string]] | test.py:22 | test.py:22:28:22:29 | ll | | -| Taint [[externally controlled string]] | test.py:19 | test.py:19:10:19:18 | List | | --> | Taint [[externally controlled string]] | test.py:26 | test.py:26:28:26:29 | ll | | -| Taint [[externally controlled string]] | test.py:19 | test.py:19:10:19:18 | List | | --> | Taint [[externally controlled string]] | test.py:30 | test.py:30:28:30:29 | ll | | -| Taint [[externally controlled string]] | test.py:22 | test.py:22:28:22:29 | ll | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:22:23:22 | b | | -| Taint [[externally controlled string]] | test.py:22 | test.py:22:28:22:29 | ll | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:25:23:25 | c | | -| Taint [[externally controlled string]] | test.py:22 | test.py:22:28:22:29 | ll | | --> | Taint externally controlled string | test.py:23 | test.py:23:10:23:11 | a1 | | -| Taint [[externally controlled string]] | test.py:22 | test.py:22:28:22:29 | ll | | --> | Taint externally controlled string | test.py:23 | test.py:23:14:23:15 | a2 | | -| Taint [[externally controlled string]] | test.py:22 | test.py:22:28:22:29 | ll | | --> | Taint externally controlled string | test.py:23 | test.py:23:18:23:19 | a3 | | -| Taint [[externally controlled string]] | test.py:26 | test.py:26:28:26:29 | ll | | --> | Taint [externally controlled string] | test.py:27 | test.py:27:22:27:22 | b | | -| Taint [[externally controlled string]] | test.py:26 | test.py:26:28:26:29 | ll | | --> | Taint [externally controlled string] | test.py:27 | test.py:27:25:27:25 | c | | -| Taint [[externally controlled string]] | test.py:26 | test.py:26:28:26:29 | ll | | --> | Taint externally controlled string | test.py:27 | test.py:27:10:27:11 | a1 | | -| Taint [[externally controlled string]] | test.py:26 | test.py:26:28:26:29 | ll | | --> | Taint externally controlled string | test.py:27 | test.py:27:14:27:15 | a2 | | -| Taint [[externally controlled string]] | test.py:26 | test.py:26:28:26:29 | ll | | --> | Taint externally controlled string | test.py:27 | test.py:27:18:27:19 | a3 | | -| Taint [[externally controlled string]] | test.py:30 | test.py:30:28:30:29 | ll | | --> | Taint [externally controlled string] | test.py:31 | test.py:31:22:31:22 | b | | -| Taint [[externally controlled string]] | test.py:30 | test.py:30:28:30:29 | ll | | --> | Taint [externally controlled string] | test.py:31 | test.py:31:25:31:25 | c | | -| Taint [[externally controlled string]] | test.py:30 | test.py:30:28:30:29 | ll | | --> | Taint externally controlled string | test.py:31 | test.py:31:10:31:11 | a1 | | -| Taint [[externally controlled string]] | test.py:30 | test.py:30:28:30:29 | ll | | --> | Taint externally controlled string | test.py:31 | test.py:31:14:31:15 | a2 | | -| Taint [[externally controlled string]] | test.py:30 | test.py:30:28:30:29 | ll | | --> | Taint externally controlled string | test.py:31 | test.py:31:18:31:19 | a3 | | -| Taint [[externally controlled string]] | test.py:47 | test.py:47:28:47:54 | Tuple | | --> | Taint externally controlled string | test.py:48 | test.py:48:10:48:10 | a | | -| Taint [[externally controlled string]] | test.py:47 | test.py:47:28:47:54 | Tuple | | --> | Taint externally controlled string | test.py:48 | test.py:48:13:48:13 | b | | -| Taint [[externally controlled string]] | test.py:47 | test.py:47:28:47:54 | Tuple | | --> | Taint externally controlled string | test.py:48 | test.py:48:16:48:16 | c | | -| Taint [[externally controlled string]] | test.py:47 | test.py:47:28:47:54 | Tuple | | --> | Taint externally controlled string | test.py:48 | test.py:48:19:48:19 | d | | -| Taint [[externally controlled string]] | test.py:47 | test.py:47:28:47:54 | Tuple | | --> | Taint externally controlled string | test.py:48 | test.py:48:22:48:22 | e | | -| Taint [[externally controlled string]] | test.py:47 | test.py:47:28:47:54 | Tuple | | --> | Taint externally controlled string | test.py:48 | test.py:48:25:48:25 | f | | -| Taint [externally controlled string] | test.py:6 | test.py:6:9:6:20 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:7 | test.py:7:15:7:15 | l | | -| Taint [externally controlled string] | test.py:7 | test.py:7:15:7:15 | l | | --> | Taint externally controlled string | test.py:8 | test.py:8:10:8:10 | a | | -| Taint [externally controlled string] | test.py:7 | test.py:7:15:7:15 | l | | --> | Taint externally controlled string | test.py:8 | test.py:8:13:8:13 | b | | -| Taint [externally controlled string] | test.py:7 | test.py:7:15:7:15 | l | | --> | Taint externally controlled string | test.py:8 | test.py:8:16:8:16 | c | | -| Taint [externally controlled string] | test.py:12 | test.py:12:9:12:20 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:13 | test.py:13:17:13:17 | l | | -| Taint [externally controlled string] | test.py:13 | test.py:13:17:13:17 | l | | --> | Taint externally controlled string | test.py:14 | test.py:14:10:14:10 | a | | -| Taint [externally controlled string] | test.py:13 | test.py:13:17:13:17 | l | | --> | Taint externally controlled string | test.py:14 | test.py:14:13:14:13 | b | | -| Taint [externally controlled string] | test.py:13 | test.py:13:17:13:17 | l | | --> | Taint externally controlled string | test.py:14 | test.py:14:16:14:16 | c | | -| Taint [externally controlled string] | test.py:18 | test.py:18:9:18:20 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:19 | test.py:19:11:19:11 | l | | -| Taint [externally controlled string] | test.py:18 | test.py:18:9:18:20 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:19 | test.py:19:14:19:14 | l | | -| Taint [externally controlled string] | test.py:18 | test.py:18:9:18:20 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:19 | test.py:19:17:19:17 | l | | -| Taint [externally controlled string] | test.py:19 | test.py:19:11:19:11 | l | | --> | Taint [[externally controlled string]] | test.py:19 | test.py:19:10:19:18 | List | | -| Taint [externally controlled string] | test.py:19 | test.py:19:14:19:14 | l | | --> | Taint [[externally controlled string]] | test.py:19 | test.py:19:10:19:18 | List | | -| Taint [externally controlled string] | test.py:19 | test.py:19:17:19:17 | l | | --> | Taint [[externally controlled string]] | test.py:19 | test.py:19:10:19:18 | List | | -| Taint [externally controlled string] | test.py:43 | test.py:43:20:43:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:47 | test.py:47:28:47:39 | tainted_list | | -| Taint [externally controlled string] | test.py:47 | test.py:47:28:47:39 | tainted_list | | --> | Taint [[externally controlled string]] | test.py:47 | test.py:47:28:47:54 | Tuple | | -| Taint [externally controlled string] | test.py:55 | test.py:55:27:55:38 | TAINTED_LIST | | --> | Taint [[externally controlled string]] | test.py:55 | test.py:55:25:55:40 | List | | diff --git a/python/ql/test/library-tests/taint/unpacking/TestStep.ql b/python/ql/test/library-tests/taint/unpacking/TestStep.ql deleted file mode 100644 index 177edce3498..00000000000 --- a/python/ql/test/library-tests/taint/unpacking/TestStep.ql +++ /dev/null @@ -1,11 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import Taint - -from TaintedNode n, TaintedNode s -where - n.getLocation().getFile().getShortName() = "test.py" and - s.getLocation().getFile().getShortName() = "test.py" and - s = n.getASuccessor() -select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getAstNode(), n.getContext(), - " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), s.getAstNode(), s.getContext() diff --git a/python/ql/test/library-tests/taint/unpacking/TestTaint.expected b/python/ql/test/library-tests/taint/unpacking/TestTaint.expected deleted file mode 100644 index d1bad70f811..00000000000 --- a/python/ql/test/library-tests/taint/unpacking/TestTaint.expected +++ /dev/null @@ -1,33 +0,0 @@ -| test.py:8 | unpacking | a | externally controlled string | -| test.py:8 | unpacking | b | externally controlled string | -| test.py:8 | unpacking | c | externally controlled string | -| test.py:14 | unpacking_to_list | a | externally controlled string | -| test.py:14 | unpacking_to_list | b | externally controlled string | -| test.py:14 | unpacking_to_list | c | externally controlled string | -| test.py:23 | nested | a1 | externally controlled string | -| test.py:23 | nested | a2 | externally controlled string | -| test.py:23 | nested | a3 | externally controlled string | -| test.py:23 | nested | b | [externally controlled string] | -| test.py:23 | nested | c | [externally controlled string] | -| test.py:27 | nested | a1 | externally controlled string | -| test.py:27 | nested | a2 | externally controlled string | -| test.py:27 | nested | a3 | externally controlled string | -| test.py:27 | nested | b | [externally controlled string] | -| test.py:27 | nested | c | [externally controlled string] | -| test.py:31 | nested | a1 | externally controlled string | -| test.py:31 | nested | a2 | externally controlled string | -| test.py:31 | nested | a3 | externally controlled string | -| test.py:31 | nested | b | [externally controlled string] | -| test.py:31 | nested | c | [externally controlled string] | -| test.py:38 | unpack_from_set | a | NO TAINT | -| test.py:38 | unpack_from_set | b | NO TAINT | -| test.py:38 | unpack_from_set | c | NO TAINT | -| test.py:48 | contrived_1 | a | externally controlled string | -| test.py:48 | contrived_1 | b | externally controlled string | -| test.py:48 | contrived_1 | c | externally controlled string | -| test.py:48 | contrived_1 | d | externally controlled string | -| test.py:48 | contrived_1 | e | externally controlled string | -| test.py:48 | contrived_1 | f | externally controlled string | -| test.py:56 | contrived_2 | a | NO TAINT | -| test.py:56 | contrived_2 | b | NO TAINT | -| test.py:56 | contrived_2 | c | NO TAINT | diff --git a/python/ql/test/library-tests/taint/unpacking/TestTaint.ql b/python/ql/test/library-tests/taint/unpacking/TestTaint.ql deleted file mode 100644 index 47883578516..00000000000 --- a/python/ql/test/library-tests/taint/unpacking/TestTaint.ql +++ /dev/null @@ -1,19 +0,0 @@ -import python -import semmle.python.dataflow.TaintTracking -import Taint - -from Call call, Expr arg, string taint_string -where - call.getLocation().getFile().getShortName() = "test.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) - ) -select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string diff --git a/python/ql/test/library-tests/taint/unpacking/test.py b/python/ql/test/library-tests/taint/unpacking/test.py deleted file mode 100644 index df3961ad6ab..00000000000 --- a/python/ql/test/library-tests/taint/unpacking/test.py +++ /dev/null @@ -1,58 +0,0 @@ -def test(*args): - pass - - -def unpacking(): - l = TAINTED_LIST - a, b, c = l - test(a, b, c) - - -def unpacking_to_list(): - l = TAINTED_LIST - [a, b, c] = l - test(a, b, c) - - -def nested(): - l = TAINTED_LIST - ll = [l, l, l] - - # list - [[a1, a2, a3], b, c] = ll - test(a1, a2, a3, b, c) - - # tuple - ((a1, a2, a3), b, c) = ll - test(a1, a2, a3, b, c) - - # mixed - [(a1, a2, a3), b, c] = ll - test(a1, a2, a3, b, c) - - -def unpack_from_set(): - # no guarantee on ordering ... don't know why you would ever do this - a, b, c = {"foo", "bar", TAINTED_STRING} - # either all should be tainted, or none of them - test(a, b, c) - - -def contrived_1(): - # A contrived example. Don't know why anyone would ever actually do this. - tainted_list = TAINTED_LIST - no_taint_list = [1,2,3] - - # We don't handle this case currently, since we mark `d`, `e` and `f` as tainted. - (a, b, c), (d, e, f) = tainted_list, no_taint_list - test(a, b, c, d, e, f) - - -def contrived_2(): - # A contrived example. Don't know why anyone would ever actually do this. - - # We currently only handle taint nested 2 levels. - [[[ (a,b,c) ]]] = [[[ TAINTED_LIST ]]] - test(a, b, c) - -# For Python 3, see https://www.python.org/dev/peps/pep-3132/ From 3a436d1f84acd3ac1f1c563324909d14e1d24010 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 12 Jun 2023 11:56:44 +0200 Subject: [PATCH 087/364] do a quick-and-dirty conversion of py/hardcoded-credentials to the new dataflow library --- .../Security/CWE-798/HardcodedCredentials.ql | 39 +++++++------------ .../HardcodedCredentials.expected | 20 +++++++--- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql index 4c9818e91f8..d1d29a78ff5 100644 --- a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -13,13 +13,10 @@ */ import python -import semmle.python.security.Paths -import semmle.python.dataflow.TaintTracking +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking import semmle.python.filters.Tests - -class HardcodedValue extends TaintKind { - HardcodedValue() { this = "hard coded value" } -} +import DataFlow::PathGraph bindingset[char, fraction] predicate fewer_characters_than(StrConst str, string char, float fraction) { @@ -78,31 +75,27 @@ predicate maybeCredential(ControlFlowNode f) { ) } -class HardcodedValueSource extends TaintSource { - HardcodedValueSource() { maybeCredential(this) } - - override predicate isSourceOf(TaintKind kind) { kind instanceof HardcodedValue } +class HardcodedValueSource extends DataFlow::Node { + HardcodedValueSource() { maybeCredential(this.asCfgNode()) } } -class CredentialSink extends TaintSink { +class CredentialSink extends DataFlow::Node { CredentialSink() { exists(string name | name.regexpMatch(getACredentialRegex()) and not name.matches("%file") | - any(FunctionValue func).getNamedArgumentForCall(_, name) = this + any(FunctionValue func).getNamedArgumentForCall(_, name) = this.asCfgNode() or - exists(Keyword k | k.getArg() = name and k.getValue().getAFlowNode() = this) + exists(Keyword k | k.getArg() = name and k.getValue().getAFlowNode() = this.asCfgNode()) or exists(CompareNode cmp, NameNode n | n.getId() = name | - cmp.operands(this, any(Eq eq), n) + cmp.operands(this.asCfgNode(), any(Eq eq), n) or - cmp.operands(n, any(Eq eq), this) + cmp.operands(n, any(Eq eq), this.asCfgNode()) ) ) } - - override predicate sinks(TaintKind kind) { kind instanceof HardcodedValue } } /** @@ -118,16 +111,14 @@ private string getACredentialRegex() { class HardcodedCredentialsConfiguration extends TaintTracking::Configuration { HardcodedCredentialsConfiguration() { this = "Hardcoded credentials configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof HardcodedValueSource - } + override predicate isSource(DataFlow::Node source) { source instanceof HardcodedValueSource } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof CredentialSink } + override predicate isSink(DataFlow::Node sink) { sink instanceof CredentialSink } } -from HardcodedCredentialsConfiguration config, TaintedPathSource src, TaintedPathSink sink +from HardcodedCredentialsConfiguration config, DataFlow::PathNode src, DataFlow::PathNode sink where config.hasFlowPath(src, sink) and - not any(TestScope test).contains(src.getAstNode()) -select src.getSource(), src, sink, "This hardcoded value is $@.", sink.getNode(), + not any(TestScope test).contains(src.getNode().asCfgNode().getNode()) +select src.getNode(), src, sink, "This hardcoded value is $@.", sink.getNode(), "used as credentials" diff --git a/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.expected b/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.expected index efea6e2f054..61251a633e2 100644 --- a/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.expected +++ b/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.expected @@ -1,8 +1,16 @@ edges -| test.py:5:12:5:24 | hard coded value | test.py:14:18:14:25 | hard coded value | -| test.py:5:12:5:24 | hard coded value | test.py:14:18:14:25 | hard coded value | -| test.py:6:12:6:25 | hard coded value | test.py:15:18:15:25 | hard coded value | -| test.py:6:12:6:25 | hard coded value | test.py:15:18:15:25 | hard coded value | +| test.py:5:1:5:8 | GSSA Variable USERNAME | test.py:14:18:14:25 | ControlFlowNode for USERNAME | +| test.py:5:12:5:24 | ControlFlowNode for Str | test.py:5:1:5:8 | GSSA Variable USERNAME | +| test.py:6:1:6:8 | GSSA Variable PASSWORD | test.py:15:18:15:25 | ControlFlowNode for PASSWORD | +| test.py:6:12:6:25 | ControlFlowNode for Str | test.py:6:1:6:8 | GSSA Variable PASSWORD | +nodes +| test.py:5:1:5:8 | GSSA Variable USERNAME | semmle.label | GSSA Variable USERNAME | +| test.py:5:12:5:24 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str | +| test.py:6:1:6:8 | GSSA Variable PASSWORD | semmle.label | GSSA Variable PASSWORD | +| test.py:6:12:6:25 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str | +| test.py:14:18:14:25 | ControlFlowNode for USERNAME | semmle.label | ControlFlowNode for USERNAME | +| test.py:15:18:15:25 | ControlFlowNode for PASSWORD | semmle.label | ControlFlowNode for PASSWORD | +subpaths #select -| test.py:5:12:5:24 | Str | test.py:5:12:5:24 | hard coded value | test.py:14:18:14:25 | hard coded value | This hardcoded value is $@. | test.py:14:18:14:25 | USERNAME | used as credentials | -| test.py:6:12:6:25 | Str | test.py:6:12:6:25 | hard coded value | test.py:15:18:15:25 | hard coded value | This hardcoded value is $@. | test.py:15:18:15:25 | PASSWORD | used as credentials | +| test.py:5:12:5:24 | ControlFlowNode for Str | test.py:5:12:5:24 | ControlFlowNode for Str | test.py:14:18:14:25 | ControlFlowNode for USERNAME | This hardcoded value is $@. | test.py:14:18:14:25 | ControlFlowNode for USERNAME | used as credentials | +| test.py:6:12:6:25 | ControlFlowNode for Str | test.py:6:12:6:25 | ControlFlowNode for Str | test.py:15:18:15:25 | ControlFlowNode for PASSWORD | This hardcoded value is $@. | test.py:15:18:15:25 | ControlFlowNode for PASSWORD | used as credentials | From e463819bc2873e921df69e2cdb8b268a8e96118c Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 12 Jun 2023 14:43:48 +0200 Subject: [PATCH 088/364] get `ParamSource.ql` to compile by deleting import that got deleted - I have no if this is a good change --- python/ql/test/library-tests/taint/general/ParamSource.ql | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/ql/test/library-tests/taint/general/ParamSource.ql b/python/ql/test/library-tests/taint/general/ParamSource.ql index 7ac2b7699ef..9ebc909cc28 100644 --- a/python/ql/test/library-tests/taint/general/ParamSource.ql +++ b/python/ql/test/library-tests/taint/general/ParamSource.ql @@ -1,7 +1,5 @@ import python import semmle.python.dataflow.TaintTracking -/* Standard library sink */ -import semmle.python.security.injection.Command class TestKind extends TaintKind { TestKind() { this = "test" } From 6e001ec062a23cead042d5ec1a13840042a5b0ec Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 12 Jun 2023 14:47:22 +0200 Subject: [PATCH 089/364] deprecate `SqlInjectionSink` - it's not used anywhere --- python/ql/lib/semmle/python/security/SQL.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/security/SQL.qll b/python/ql/lib/semmle/python/security/SQL.qll index 4d2ef6218cc..6485402b78a 100644 --- a/python/ql/lib/semmle/python/security/SQL.qll +++ b/python/ql/lib/semmle/python/security/SQL.qll @@ -1,4 +1,4 @@ import python import semmle.python.dataflow.TaintTracking -abstract class SqlInjectionSink extends TaintSink { } +abstract deprecated class SqlInjectionSink extends TaintSink { } From 1f8f111ef6a64e01efa2a9dac374fd23d1be32f7 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 12 Jun 2023 14:59:18 +0200 Subject: [PATCH 090/364] reintroduce DataFlowType - otherwise nothing in the old DataFlow library would compile --- .../ql/lib/semmle/python/dataflow/old/TaintTracking.qll | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll b/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll index 0ce4bc27790..d0293522404 100644 --- a/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll +++ b/python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll @@ -664,6 +664,14 @@ module DataFlow { } } +deprecated private class DataFlowType extends TaintKind { + // this only exists to avoid an empty recursion error in the type checker + DataFlowType() { + this = "Data flow" and + 1 = 2 + } +} + pragma[noinline] private predicate dict_construct(ControlFlowNode itemnode, ControlFlowNode dictnode) { dictnode.(DictNode).getAValue() = itemnode From bfe7e62f35f8485759d0a6c7e81073b5d7e6e5c7 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 12 Jun 2023 20:15:40 +0200 Subject: [PATCH 091/364] update some expected outputs - some tests no longer have an edges relation - and XsltSinks lost a result --- .../Security/CWE-091/XsltSinks.expected | 1 - .../taint/config/RockPaperScissors.expected | 96 ------------------- .../taint/config/Simple.expected | 96 ------------------- .../taint/example/ExampleConfig.expected | 26 ----- 4 files changed, 219 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091/XsltSinks.expected b/python/ql/test/experimental/query-tests/Security/CWE-091/XsltSinks.expected index 7150b3046e2..dec055bc8e0 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-091/XsltSinks.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-091/XsltSinks.expected @@ -1,4 +1,3 @@ -| xslt.py:14:29:14:37 | lxml.etree.parse.xslt | lxml etree xml | | xsltInjection.py:12:28:12:36 | lxml.etree.XSLT | lxml etree xml | | xsltInjection.py:21:29:21:37 | lxml.etree.parse.xslt | lxml etree xml | | xsltInjection.py:31:24:31:32 | lxml.etree.parse.xslt | lxml etree xml | diff --git a/python/ql/test/library-tests/taint/config/RockPaperScissors.expected b/python/ql/test/library-tests/taint/config/RockPaperScissors.expected index 0639e4bf227..ae34dcd904e 100644 --- a/python/ql/test/library-tests/taint/config/RockPaperScissors.expected +++ b/python/ql/test/library-tests/taint/config/RockPaperScissors.expected @@ -1,99 +1,3 @@ -edges -| carrier.py:17:9:17:31 | .attr = simple.test | carrier.py:18:10:18:10 | .attr = simple.test | -| carrier.py:17:25:17:30 | simple.test | carrier.py:17:9:17:31 | .attr = simple.test | -| carrier.py:18:10:18:10 | .attr = simple.test | carrier.py:18:10:18:15 | simple.test | -| carrier.py:21:9:21:28 | explicit.carrier | carrier.py:22:10:22:10 | explicit.carrier | -| carrier.py:22:10:22:10 | explicit.carrier | carrier.py:22:10:22:22 | simple.test | -| carrier.py:25:9:25:36 | .attr = simple.test | carrier.py:26:10:26:10 | .attr = simple.test | -| carrier.py:25:13:25:35 | .attr = simple.test | carrier.py:25:9:25:36 | .attr = simple.test | -| carrier.py:25:29:25:34 | simple.test | carrier.py:25:13:25:35 | .attr = simple.test | -| carrier.py:26:10:26:10 | .attr = simple.test | carrier.py:26:10:26:21 | simple.test | -| carrier.py:29:9:29:33 | explicit.carrier | carrier.py:30:10:30:10 | explicit.carrier | -| carrier.py:29:13:29:32 | explicit.carrier | carrier.py:29:9:29:33 | explicit.carrier | -| carrier.py:30:10:30:10 | explicit.carrier | carrier.py:30:10:30:22 | simple.test | -| carrier.py:33:9:33:45 | .attr = explicit.carrier | carrier.py:34:9:34:9 | .attr = explicit.carrier | -| carrier.py:33:25:33:44 | explicit.carrier | carrier.py:33:9:33:45 | .attr = explicit.carrier | -| carrier.py:34:9:34:9 | .attr = explicit.carrier | carrier.py:34:9:34:14 | explicit.carrier | -| carrier.py:34:9:34:14 | explicit.carrier | carrier.py:35:10:35:10 | explicit.carrier | -| carrier.py:35:10:35:10 | explicit.carrier | carrier.py:35:10:35:22 | simple.test | -| deep.py:20:5:20:14 | simple.test | deep.py:22:6:22:6 | simple.test | -| deep.py:20:8:20:13 | simple.test | deep.py:20:5:20:14 | simple.test | -| module.py:3:13:3:18 | simple.test | test.py:85:8:85:13 | .dangerous = simple.test | -| module.py:3:13:3:18 | simple.test | test.py:88:9:88:14 | .dangerous = simple.test | -| module.py:3:13:3:18 | simple.test | test.py:110:11:110:16 | .dangerous = simple.test | -| module.py:3:13:3:18 | simple.test | test.py:115:11:115:16 | .dangerous = simple.test | -| module.py:3:13:3:18 | simple.test | test.py:155:20:155:38 | simple.test | -| module.py:7:12:7:17 | simple.test | test.py:100:9:100:31 | simple.test | -| rockpaperscissors.py:24:9:24:12 | rock | rockpaperscissors.py:25:9:25:9 | rock | -| rockpaperscissors.py:25:9:25:9 | rock | rockpaperscissors.py:25:9:25:16 | scissors | -| rockpaperscissors.py:25:9:25:16 | scissors | rockpaperscissors.py:25:9:25:23 | paper | -| rockpaperscissors.py:25:9:25:23 | paper | rockpaperscissors.py:26:14:26:14 | paper | -| sanitizer.py:9:9:9:20 | SQL injection | sanitizer.py:13:19:13:19 | SQL injection | -| sanitizer.py:16:9:16:20 | Command injection | sanitizer.py:20:20:20:20 | Command injection | -| sanitizer.py:24:9:24:20 | SQL injection | sanitizer.py:26:19:26:19 | SQL injection | -| sanitizer.py:24:9:24:20 | SQL injection | sanitizer.py:28:19:28:19 | SQL injection | -| sanitizer.py:31:9:31:20 | Command injection | sanitizer.py:33:20:33:20 | Command injection | -| sanitizer.py:31:9:31:20 | Command injection | sanitizer.py:35:20:35:20 | Command injection | -| test.py:6:9:6:14 | simple.test | test.py:7:10:7:10 | simple.test | -| test.py:10:12:10:17 | simple.test | test.py:16:9:16:16 | simple.test | -| test.py:10:12:10:17 | simple.test | test.py:24:9:24:16 | simple.test | -| test.py:10:12:10:17 | simple.test | test.py:44:12:44:22 | simple.test | -| test.py:12:10:12:12 | simple.test | test.py:13:10:13:12 | simple.test | -| test.py:16:9:16:16 | simple.test | test.py:17:10:17:10 | simple.test | -| test.py:20:9:20:14 | simple.test | test.py:21:10:21:10 | simple.test | -| test.py:21:10:21:10 | simple.test | test.py:12:10:12:12 | simple.test | -| test.py:24:9:24:16 | simple.test | test.py:25:10:25:10 | simple.test | -| test.py:25:10:25:10 | simple.test | test.py:12:10:12:12 | simple.test | -| test.py:37:13:37:18 | simple.test | test.py:41:14:41:14 | simple.test | -| test.py:44:12:44:22 | simple.test | test.py:54:9:54:17 | simple.test | -| test.py:46:11:46:13 | simple.test | test.py:47:10:47:12 | simple.test | -| test.py:47:10:47:12 | simple.test | test.py:12:10:12:12 | simple.test | -| test.py:49:17:49:19 | simple.test | test.py:51:14:51:16 | simple.test | -| test.py:51:14:51:16 | simple.test | test.py:12:10:12:12 | simple.test | -| test.py:54:9:54:17 | simple.test | test.py:55:11:55:11 | simple.test | -| test.py:55:11:55:11 | simple.test | test.py:46:11:46:13 | simple.test | -| test.py:62:13:62:18 | simple.test | test.py:63:17:63:17 | simple.test | -| test.py:63:17:63:17 | simple.test | test.py:49:17:49:19 | simple.test | -| test.py:67:13:67:18 | simple.test | test.py:70:17:70:17 | simple.test | -| test.py:70:17:70:17 | simple.test | test.py:49:17:49:19 | simple.test | -| test.py:76:9:76:14 | simple.test | test.py:77:13:77:13 | simple.test | -| test.py:77:9:77:14 | simple.test | test.py:78:10:78:10 | simple.test | -| test.py:77:13:77:13 | simple.test | test.py:77:9:77:14 | simple.test | -| test.py:85:8:85:13 | .dangerous = simple.test | test.py:88:9:88:14 | .dangerous = simple.test | -| test.py:85:8:85:13 | .dangerous = simple.test | test.py:110:11:110:16 | .dangerous = simple.test | -| test.py:85:8:85:13 | .dangerous = simple.test | test.py:115:11:115:16 | .dangerous = simple.test | -| test.py:88:9:88:14 | .dangerous = simple.test | test.py:88:9:88:24 | simple.test | -| test.py:88:9:88:24 | simple.test | test.py:89:10:89:10 | simple.test | -| test.py:100:9:100:31 | simple.test | test.py:101:10:101:10 | simple.test | -| test.py:105:12:105:14 | .x = simple.test | test.py:106:10:106:12 | .x = simple.test | -| test.py:106:10:106:12 | .x = simple.test | test.py:106:10:106:14 | simple.test | -| test.py:110:11:110:16 | .dangerous = simple.test | test.py:110:11:110:26 | simple.test | -| test.py:110:11:110:26 | simple.test | test.py:111:10:111:10 | .x = simple.test | -| test.py:111:10:111:10 | .x = simple.test | test.py:111:10:111:12 | simple.test | -| test.py:115:11:115:16 | .dangerous = simple.test | test.py:115:11:115:26 | simple.test | -| test.py:115:11:115:26 | simple.test | test.py:116:13:116:13 | .x = simple.test | -| test.py:116:9:116:14 | .x = simple.test | test.py:117:12:117:12 | .x = simple.test | -| test.py:116:13:116:13 | .x = simple.test | test.py:116:9:116:14 | .x = simple.test | -| test.py:117:12:117:12 | .x = simple.test | test.py:105:12:105:14 | .x = simple.test | -| test.py:126:13:126:25 | simple.test | test.py:130:21:130:21 | simple.test | -| test.py:128:13:128:18 | simple.test | test.py:132:14:132:14 | simple.test | -| test.py:155:20:155:38 | simple.test | test.py:156:6:156:11 | simple.test | -| test.py:159:10:159:15 | simple.test | test.py:160:14:160:14 | simple.test | -| test.py:163:9:163:14 | simple.test | test.py:165:10:165:10 | simple.test | -| test.py:178:9:178:14 | simple.test | test.py:180:14:180:14 | simple.test | -| test.py:178:9:178:14 | simple.test | test.py:186:14:186:14 | simple.test | -| test.py:195:9:195:14 | simple.test | test.py:197:14:197:14 | simple.test | -| test.py:195:9:195:14 | simple.test | test.py:199:14:199:14 | simple.test | -| test.py:208:11:208:18 | sequence of simple.test | test.py:209:14:209:16 | sequence of simple.test | -| test.py:208:12:208:17 | simple.test | test.py:208:11:208:18 | sequence of simple.test | -| test.py:209:5:209:17 | simple.test | test.py:210:15:210:15 | simple.test | -| test.py:209:14:209:16 | sequence of simple.test | test.py:209:5:209:17 | simple.test | -| test.py:210:15:210:15 | simple.test | test.py:213:14:213:32 | iterable.simple | -| test.py:210:15:210:15 | simple.test | test.py:213:14:213:32 | sequence of simple.test | -| test.py:213:5:213:33 | simple.test | test.py:214:14:214:14 | simple.test | -| test.py:213:14:213:32 | iterable.simple | test.py:213:5:213:33 | simple.test | -| test.py:213:14:213:32 | sequence of simple.test | test.py:213:5:213:33 | simple.test | -#select | rockpaperscissors.py:13:10:13:17 | SCISSORS | rockpaperscissors.py:13:10:13:17 | scissors | rockpaperscissors.py:13:10:13:17 | scissors | $@ loses to $@. | rockpaperscissors.py:13:10:13:17 | SCISSORS | scissors | rockpaperscissors.py:13:10:13:17 | SCISSORS | scissors | | rockpaperscissors.py:16:11:16:14 | ROCK | rockpaperscissors.py:16:11:16:14 | rock | rockpaperscissors.py:16:11:16:14 | rock | $@ loses to $@. | rockpaperscissors.py:16:11:16:14 | ROCK | rock | rockpaperscissors.py:16:11:16:14 | ROCK | rock | | rockpaperscissors.py:26:14:26:14 | y | rockpaperscissors.py:24:9:24:12 | rock | rockpaperscissors.py:26:14:26:14 | paper | $@ loses to $@. | rockpaperscissors.py:24:9:24:12 | ROCK | rock | rockpaperscissors.py:26:14:26:14 | y | paper | diff --git a/python/ql/test/library-tests/taint/config/Simple.expected b/python/ql/test/library-tests/taint/config/Simple.expected index 108f0f12015..78a86d7a0c8 100644 --- a/python/ql/test/library-tests/taint/config/Simple.expected +++ b/python/ql/test/library-tests/taint/config/Simple.expected @@ -1,99 +1,3 @@ -edges -| carrier.py:17:9:17:31 | .attr = simple.test | carrier.py:18:10:18:10 | .attr = simple.test | -| carrier.py:17:25:17:30 | simple.test | carrier.py:17:9:17:31 | .attr = simple.test | -| carrier.py:18:10:18:10 | .attr = simple.test | carrier.py:18:10:18:15 | simple.test | -| carrier.py:21:9:21:28 | explicit.carrier | carrier.py:22:10:22:10 | explicit.carrier | -| carrier.py:22:10:22:10 | explicit.carrier | carrier.py:22:10:22:22 | simple.test | -| carrier.py:25:9:25:36 | .attr = simple.test | carrier.py:26:10:26:10 | .attr = simple.test | -| carrier.py:25:13:25:35 | .attr = simple.test | carrier.py:25:9:25:36 | .attr = simple.test | -| carrier.py:25:29:25:34 | simple.test | carrier.py:25:13:25:35 | .attr = simple.test | -| carrier.py:26:10:26:10 | .attr = simple.test | carrier.py:26:10:26:21 | simple.test | -| carrier.py:29:9:29:33 | explicit.carrier | carrier.py:30:10:30:10 | explicit.carrier | -| carrier.py:29:13:29:32 | explicit.carrier | carrier.py:29:9:29:33 | explicit.carrier | -| carrier.py:30:10:30:10 | explicit.carrier | carrier.py:30:10:30:22 | simple.test | -| carrier.py:33:9:33:45 | .attr = explicit.carrier | carrier.py:34:9:34:9 | .attr = explicit.carrier | -| carrier.py:33:25:33:44 | explicit.carrier | carrier.py:33:9:33:45 | .attr = explicit.carrier | -| carrier.py:34:9:34:9 | .attr = explicit.carrier | carrier.py:34:9:34:14 | explicit.carrier | -| carrier.py:34:9:34:14 | explicit.carrier | carrier.py:35:10:35:10 | explicit.carrier | -| carrier.py:35:10:35:10 | explicit.carrier | carrier.py:35:10:35:22 | simple.test | -| deep.py:20:5:20:14 | simple.test | deep.py:22:6:22:6 | simple.test | -| deep.py:20:8:20:13 | simple.test | deep.py:20:5:20:14 | simple.test | -| module.py:3:13:3:18 | simple.test | test.py:85:8:85:13 | .dangerous = simple.test | -| module.py:3:13:3:18 | simple.test | test.py:88:9:88:14 | .dangerous = simple.test | -| module.py:3:13:3:18 | simple.test | test.py:110:11:110:16 | .dangerous = simple.test | -| module.py:3:13:3:18 | simple.test | test.py:115:11:115:16 | .dangerous = simple.test | -| module.py:3:13:3:18 | simple.test | test.py:155:20:155:38 | simple.test | -| module.py:7:12:7:17 | simple.test | test.py:100:9:100:31 | simple.test | -| rockpaperscissors.py:24:9:24:12 | rock | rockpaperscissors.py:25:9:25:9 | rock | -| rockpaperscissors.py:25:9:25:9 | rock | rockpaperscissors.py:25:9:25:16 | scissors | -| rockpaperscissors.py:25:9:25:16 | scissors | rockpaperscissors.py:25:9:25:23 | paper | -| rockpaperscissors.py:25:9:25:23 | paper | rockpaperscissors.py:26:14:26:14 | paper | -| sanitizer.py:9:9:9:20 | SQL injection | sanitizer.py:13:19:13:19 | SQL injection | -| sanitizer.py:16:9:16:20 | Command injection | sanitizer.py:20:20:20:20 | Command injection | -| sanitizer.py:24:9:24:20 | SQL injection | sanitizer.py:26:19:26:19 | SQL injection | -| sanitizer.py:24:9:24:20 | SQL injection | sanitizer.py:28:19:28:19 | SQL injection | -| sanitizer.py:31:9:31:20 | Command injection | sanitizer.py:33:20:33:20 | Command injection | -| sanitizer.py:31:9:31:20 | Command injection | sanitizer.py:35:20:35:20 | Command injection | -| test.py:6:9:6:14 | simple.test | test.py:7:10:7:10 | simple.test | -| test.py:10:12:10:17 | simple.test | test.py:16:9:16:16 | simple.test | -| test.py:10:12:10:17 | simple.test | test.py:24:9:24:16 | simple.test | -| test.py:10:12:10:17 | simple.test | test.py:44:12:44:22 | simple.test | -| test.py:12:10:12:12 | simple.test | test.py:13:10:13:12 | simple.test | -| test.py:16:9:16:16 | simple.test | test.py:17:10:17:10 | simple.test | -| test.py:20:9:20:14 | simple.test | test.py:21:10:21:10 | simple.test | -| test.py:21:10:21:10 | simple.test | test.py:12:10:12:12 | simple.test | -| test.py:24:9:24:16 | simple.test | test.py:25:10:25:10 | simple.test | -| test.py:25:10:25:10 | simple.test | test.py:12:10:12:12 | simple.test | -| test.py:37:13:37:18 | simple.test | test.py:41:14:41:14 | simple.test | -| test.py:44:12:44:22 | simple.test | test.py:54:9:54:17 | simple.test | -| test.py:46:11:46:13 | simple.test | test.py:47:10:47:12 | simple.test | -| test.py:47:10:47:12 | simple.test | test.py:12:10:12:12 | simple.test | -| test.py:49:17:49:19 | simple.test | test.py:51:14:51:16 | simple.test | -| test.py:51:14:51:16 | simple.test | test.py:12:10:12:12 | simple.test | -| test.py:54:9:54:17 | simple.test | test.py:55:11:55:11 | simple.test | -| test.py:55:11:55:11 | simple.test | test.py:46:11:46:13 | simple.test | -| test.py:62:13:62:18 | simple.test | test.py:63:17:63:17 | simple.test | -| test.py:63:17:63:17 | simple.test | test.py:49:17:49:19 | simple.test | -| test.py:67:13:67:18 | simple.test | test.py:70:17:70:17 | simple.test | -| test.py:70:17:70:17 | simple.test | test.py:49:17:49:19 | simple.test | -| test.py:76:9:76:14 | simple.test | test.py:77:13:77:13 | simple.test | -| test.py:77:9:77:14 | simple.test | test.py:78:10:78:10 | simple.test | -| test.py:77:13:77:13 | simple.test | test.py:77:9:77:14 | simple.test | -| test.py:85:8:85:13 | .dangerous = simple.test | test.py:88:9:88:14 | .dangerous = simple.test | -| test.py:85:8:85:13 | .dangerous = simple.test | test.py:110:11:110:16 | .dangerous = simple.test | -| test.py:85:8:85:13 | .dangerous = simple.test | test.py:115:11:115:16 | .dangerous = simple.test | -| test.py:88:9:88:14 | .dangerous = simple.test | test.py:88:9:88:24 | simple.test | -| test.py:88:9:88:24 | simple.test | test.py:89:10:89:10 | simple.test | -| test.py:100:9:100:31 | simple.test | test.py:101:10:101:10 | simple.test | -| test.py:105:12:105:14 | .x = simple.test | test.py:106:10:106:12 | .x = simple.test | -| test.py:106:10:106:12 | .x = simple.test | test.py:106:10:106:14 | simple.test | -| test.py:110:11:110:16 | .dangerous = simple.test | test.py:110:11:110:26 | simple.test | -| test.py:110:11:110:26 | simple.test | test.py:111:10:111:10 | .x = simple.test | -| test.py:111:10:111:10 | .x = simple.test | test.py:111:10:111:12 | simple.test | -| test.py:115:11:115:16 | .dangerous = simple.test | test.py:115:11:115:26 | simple.test | -| test.py:115:11:115:26 | simple.test | test.py:116:13:116:13 | .x = simple.test | -| test.py:116:9:116:14 | .x = simple.test | test.py:117:12:117:12 | .x = simple.test | -| test.py:116:13:116:13 | .x = simple.test | test.py:116:9:116:14 | .x = simple.test | -| test.py:117:12:117:12 | .x = simple.test | test.py:105:12:105:14 | .x = simple.test | -| test.py:126:13:126:25 | simple.test | test.py:130:21:130:21 | simple.test | -| test.py:128:13:128:18 | simple.test | test.py:132:14:132:14 | simple.test | -| test.py:155:20:155:38 | simple.test | test.py:156:6:156:11 | simple.test | -| test.py:159:10:159:15 | simple.test | test.py:160:14:160:14 | simple.test | -| test.py:163:9:163:14 | simple.test | test.py:165:10:165:10 | simple.test | -| test.py:178:9:178:14 | simple.test | test.py:180:14:180:14 | simple.test | -| test.py:178:9:178:14 | simple.test | test.py:186:14:186:14 | simple.test | -| test.py:195:9:195:14 | simple.test | test.py:197:14:197:14 | simple.test | -| test.py:195:9:195:14 | simple.test | test.py:199:14:199:14 | simple.test | -| test.py:208:11:208:18 | sequence of simple.test | test.py:209:14:209:16 | sequence of simple.test | -| test.py:208:12:208:17 | simple.test | test.py:208:11:208:18 | sequence of simple.test | -| test.py:209:5:209:17 | simple.test | test.py:210:15:210:15 | simple.test | -| test.py:209:14:209:16 | sequence of simple.test | test.py:209:5:209:17 | simple.test | -| test.py:210:15:210:15 | simple.test | test.py:213:14:213:32 | iterable.simple | -| test.py:210:15:210:15 | simple.test | test.py:213:14:213:32 | sequence of simple.test | -| test.py:213:5:213:33 | simple.test | test.py:214:14:214:14 | simple.test | -| test.py:213:14:213:32 | iterable.simple | test.py:213:5:213:33 | simple.test | -| test.py:213:14:213:32 | sequence of simple.test | test.py:213:5:213:33 | simple.test | -#select | carrier.py:18:10:18:15 | Attribute | carrier.py:17:25:17:30 | simple.test | carrier.py:18:10:18:15 | simple.test | $@ flows to $@. | carrier.py:17:25:17:30 | SOURCE | simple.test | carrier.py:18:10:18:15 | Attribute | simple.test | | carrier.py:26:10:26:21 | Attribute() | carrier.py:25:29:25:34 | simple.test | carrier.py:26:10:26:21 | simple.test | $@ flows to $@. | carrier.py:25:29:25:34 | SOURCE | simple.test | carrier.py:26:10:26:21 | Attribute() | simple.test | | deep.py:22:6:22:6 | x | deep.py:20:8:20:13 | simple.test | deep.py:22:6:22:6 | simple.test | $@ flows to $@. | deep.py:20:8:20:13 | SOURCE | simple.test | deep.py:22:6:22:6 | x | simple.test | diff --git a/python/ql/test/library-tests/taint/example/ExampleConfig.expected b/python/ql/test/library-tests/taint/example/ExampleConfig.expected index 5127ff1e794..ed1bd0fe0ec 100644 --- a/python/ql/test/library-tests/taint/example/ExampleConfig.expected +++ b/python/ql/test/library-tests/taint/example/ExampleConfig.expected @@ -1,29 +1,3 @@ -edges -| example.py:17:14:17:21 | Dilbert | example.py:18:13:18:18 | Dilbert | -| example.py:17:14:17:21 | Wally | example.py:18:13:18:18 | Wally | -| example.py:22:14:22:21 | Dilbert | example.py:23:20:23:25 | Dilbert | -| example.py:23:14:23:26 | Dilbert | example.py:24:13:24:18 | Dilbert | -| example.py:23:20:23:25 | Dilbert | example.py:23:14:23:26 | Dilbert | -| example.py:28:14:28:21 | Dilbert | example.py:29:13:29:18 | Dilbert | -| example.py:28:14:28:21 | Wally | example.py:29:13:29:18 | Wally | -| example.py:33:14:33:21 | Dilbert | example.py:34:24:34:29 | Dilbert | -| example.py:34:12:34:30 | .worker = Dilbert | example.py:37:20:37:23 | .worker = Dilbert | -| example.py:34:24:34:29 | Dilbert | example.py:34:12:34:30 | .worker = Dilbert | -| example.py:37:14:37:31 | Dilbert | example.py:39:13:39:18 | Dilbert | -| example.py:37:20:37:23 | .worker = Dilbert | example.py:37:20:37:30 | Dilbert | -| example.py:37:20:37:30 | Dilbert | example.py:37:14:37:31 | Dilbert | -| example.py:57:14:57:21 | Dilbert | example.py:58:22:58:27 | Dilbert | -| example.py:57:14:57:21 | Wally | example.py:58:22:58:27 | Wally | -| example.py:58:14:58:28 | Dilbert | example.py:60:13:60:18 | Dilbert | -| example.py:58:14:58:28 | Wally | example.py:60:13:60:18 | Wally | -| example.py:58:22:58:27 | Dilbert | example.py:58:14:58:28 | Dilbert | -| example.py:58:22:58:27 | Wally | example.py:58:14:58:28 | Wally | -| example.py:64:14:64:21 | Dilbert | example.py:65:20:65:25 | Dilbert | -| example.py:65:14:65:26 | Dilbert | example.py:66:22:66:27 | Dilbert | -| example.py:65:20:65:25 | Dilbert | example.py:65:14:65:26 | Dilbert | -| example.py:66:14:66:28 | Dilbert | example.py:68:13:68:18 | Dilbert | -| example.py:66:22:66:27 | Dilbert | example.py:66:14:66:28 | Dilbert | -#select | example.py:18:13:18:18 | worker | example.py:17:14:17:21 | Dilbert | example.py:18:13:18:18 | Dilbert | $@ goes to a $@. | example.py:17:14:17:21 | ENGINEER | Dilbert | example.py:18:13:18:18 | worker | meeting | | example.py:18:13:18:18 | worker | example.py:17:14:17:21 | Wally | example.py:18:13:18:18 | Wally | $@ goes to a $@. | example.py:17:14:17:21 | ENGINEER | Wally | example.py:18:13:18:18 | worker | meeting | | example.py:24:13:24:18 | worker | example.py:22:14:22:21 | Dilbert | example.py:24:13:24:18 | Dilbert | $@ goes to a $@. | example.py:22:14:22:21 | ENGINEER | Dilbert | example.py:24:13:24:18 | worker | meeting | From df61c4dd62856ab064574fba444652142d2ae295 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 12 Jun 2023 22:09:47 +0200 Subject: [PATCH 092/364] reintroduce the experiemental queries that use deprecated features --- .../ql/lib/semmle/python/security/Paths.qll | 16 + .../semmle/python/security/strings/Basic.qll | 124 +++++++ .../semmle/python/security/strings/Common.qll | 14 + .../python/security/strings/External.qll | 318 ++++++++++++++++++ .../python/security/strings/Untrusted.qll | 10 + python/ql/lib/semmle/python/web/Http.qll | 119 +++++++ .../lib/semmle/python/web/HttpConstants.qll | 7 + .../ql/lib/semmle/python/web/HttpRequest.qll | 10 + .../lib/semmle/python/web/bottle/General.qll | 46 +++ .../lib/semmle/python/web/bottle/Request.qll | 80 +++++ .../semmle/python/web/cherrypy/General.qll | 44 +++ .../semmle/python/web/cherrypy/Request.qll | 41 +++ .../lib/semmle/python/web/django/General.qll | 136 ++++++++ .../lib/semmle/python/web/django/Request.qll | 78 +++++ .../lib/semmle/python/web/falcon/General.qll | 46 +++ .../lib/semmle/python/web/falcon/Request.qll | 37 ++ .../lib/semmle/python/web/flask/General.qll | 104 ++++++ .../lib/semmle/python/web/flask/Request.qll | 80 +++++ .../lib/semmle/python/web/flask/Response.qll | 55 +++ .../lib/semmle/python/web/pyramid/Request.qll | 25 ++ .../ql/lib/semmle/python/web/pyramid/View.qll | 9 + .../lib/semmle/python/web/stdlib/Request.qll | 126 +++++++ .../lib/semmle/python/web/tornado/Request.qll | 69 ++++ .../lib/semmle/python/web/tornado/Tornado.qll | 50 +++ .../semmle/python/web/turbogears/Request.qll | 26 ++ .../python/web/turbogears/TurboGears.qll | 37 ++ .../lib/semmle/python/web/twisted/Request.qll | 30 ++ .../lib/semmle/python/web/twisted/Twisted.qll | 52 +++ .../lib/semmle/python/web/webob/Request.qll | 38 +++ .../Security/CWE-074/TemplateInjection.qhelp | 24 ++ .../Security/CWE-074/TemplateInjection.ql | 35 ++ .../experimental/Security/CWE-091/Xslt.qhelp | 18 + .../src/experimental/Security/CWE-091/Xslt.ql | 36 ++ .../src/experimental/Security/CWE-091/xslt.py | 14 + .../semmle/python/security/injection/XSLT.qll | 42 +++ .../semmle/python/templates/Airspeed.qll | 27 ++ .../semmle/python/templates/Bottle.qll | 48 +++ .../semmle/python/templates/Chameleon.qll | 29 ++ .../semmle/python/templates/Cheetah.qll | 39 +++ .../semmle/python/templates/Chevron.qll | 36 ++ .../python/templates/DjangoTemplate.qll | 35 ++ .../semmle/python/templates/FlaskTemplate.qll | 28 ++ .../semmle/python/templates/Genshi.qll | 53 +++ .../semmle/python/templates/Jinja.qll | 49 +++ .../semmle/python/templates/Mako.qll | 27 ++ .../semmle/python/templates/SSTISink.qll | 7 + .../semmle/python/templates/Ssti.qll | 13 + .../semmle/python/templates/TRender.qll | 27 ++ .../CWE-074/TemplateInjection.expected | 60 ++++ .../Security/CWE-074/TemplateInjection.qlref | 1 + .../Security/CWE-091/Xslt.expected | 47 +++ .../query-tests/Security/CWE-091/Xslt.qlref | 1 + .../Security/CWE-091/XsltSinks.expected | 1 + .../query-tests/Security/CWE-091/xslt.py | 14 + 54 files changed, 2538 insertions(+) create mode 100644 python/ql/lib/semmle/python/security/Paths.qll create mode 100644 python/ql/lib/semmle/python/security/strings/Basic.qll create mode 100644 python/ql/lib/semmle/python/security/strings/Common.qll create mode 100644 python/ql/lib/semmle/python/security/strings/External.qll create mode 100644 python/ql/lib/semmle/python/security/strings/Untrusted.qll create mode 100644 python/ql/lib/semmle/python/web/Http.qll create mode 100644 python/ql/lib/semmle/python/web/HttpConstants.qll create mode 100644 python/ql/lib/semmle/python/web/HttpRequest.qll create mode 100644 python/ql/lib/semmle/python/web/bottle/General.qll create mode 100644 python/ql/lib/semmle/python/web/bottle/Request.qll create mode 100644 python/ql/lib/semmle/python/web/cherrypy/General.qll create mode 100644 python/ql/lib/semmle/python/web/cherrypy/Request.qll create mode 100644 python/ql/lib/semmle/python/web/django/General.qll create mode 100644 python/ql/lib/semmle/python/web/django/Request.qll create mode 100644 python/ql/lib/semmle/python/web/falcon/General.qll create mode 100644 python/ql/lib/semmle/python/web/falcon/Request.qll create mode 100644 python/ql/lib/semmle/python/web/flask/General.qll create mode 100644 python/ql/lib/semmle/python/web/flask/Request.qll create mode 100644 python/ql/lib/semmle/python/web/flask/Response.qll create mode 100644 python/ql/lib/semmle/python/web/pyramid/Request.qll create mode 100644 python/ql/lib/semmle/python/web/pyramid/View.qll create mode 100644 python/ql/lib/semmle/python/web/stdlib/Request.qll create mode 100644 python/ql/lib/semmle/python/web/tornado/Request.qll create mode 100644 python/ql/lib/semmle/python/web/tornado/Tornado.qll create mode 100644 python/ql/lib/semmle/python/web/turbogears/Request.qll create mode 100644 python/ql/lib/semmle/python/web/turbogears/TurboGears.qll create mode 100644 python/ql/lib/semmle/python/web/twisted/Request.qll create mode 100644 python/ql/lib/semmle/python/web/twisted/Twisted.qll create mode 100644 python/ql/lib/semmle/python/web/webob/Request.qll create mode 100644 python/ql/src/experimental/Security/CWE-074/TemplateInjection.qhelp create mode 100644 python/ql/src/experimental/Security/CWE-074/TemplateInjection.ql create mode 100644 python/ql/src/experimental/Security/CWE-091/Xslt.qhelp create mode 100644 python/ql/src/experimental/Security/CWE-091/Xslt.ql create mode 100644 python/ql/src/experimental/Security/CWE-091/xslt.py create mode 100644 python/ql/src/experimental/semmle/python/templates/Airspeed.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Bottle.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Chameleon.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Cheetah.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Chevron.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Genshi.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Jinja.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Mako.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/SSTISink.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/Ssti.qll create mode 100644 python/ql/src/experimental/semmle/python/templates/TRender.qll create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.qlref create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.qlref create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-091/xslt.py diff --git a/python/ql/lib/semmle/python/security/Paths.qll b/python/ql/lib/semmle/python/security/Paths.qll new file mode 100644 index 00000000000..9288a1eff61 --- /dev/null +++ b/python/ql/lib/semmle/python/security/Paths.qll @@ -0,0 +1,16 @@ +import semmle.python.dataflow.Implementation + +deprecated module TaintTrackingPaths { + predicate edge(TaintTrackingNode src, TaintTrackingNode dest, string label) { + exists(TaintTrackingNode source, TaintTrackingNode sink | + source.getConfiguration().hasFlowPath(source, sink) and + source.getASuccessor*() = src and + src.getASuccessor(label) = dest and + dest.getASuccessor*() = sink + ) + } +} + +deprecated query predicate edges(TaintTrackingNode fromnode, TaintTrackingNode tonode) { + TaintTrackingPaths::edge(fromnode, tonode, _) +} diff --git a/python/ql/lib/semmle/python/security/strings/Basic.qll b/python/ql/lib/semmle/python/security/strings/Basic.qll new file mode 100644 index 00000000000..6bbae862c32 --- /dev/null +++ b/python/ql/lib/semmle/python/security/strings/Basic.qll @@ -0,0 +1,124 @@ +import python +private import Common +import semmle.python.dataflow.TaintTracking + +/** An extensible kind of taint representing any kind of string. */ +abstract deprecated class StringKind extends TaintKind { + bindingset[this] + StringKind() { this = this } + + override TaintKind getTaintOfMethodResult(string name) { + name in [ + "capitalize", "casefold", "center", "expandtabs", "format", "format_map", "ljust", "lstrip", + "lower", "replace", "rjust", "rstrip", "strip", "swapcase", "title", "upper", "zfill", + /* encode/decode is technically not correct, but close enough */ + "encode", "decode" + ] and + result = this + or + name in ["partition", "rpartition", "rsplit", "split", "splitlines"] and + result.(SequenceKind).getItem() = this + } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + result = this and + ( + slice(fromnode, tonode) or + tonode.(BinaryExprNode).getAnOperand() = fromnode or + os_path_join(fromnode, tonode) or + str_format(fromnode, tonode) or + encode_decode(fromnode, tonode) or + to_str(fromnode, tonode) or + f_string(fromnode, tonode) + ) + or + result = this and copy_call(fromnode, tonode) + } + + override ClassValue getType() { + result = Value::named("bytes") or + result = Value::named("str") or + result = Value::named("unicode") + } +} + +deprecated private class StringEqualitySanitizer extends Sanitizer { + StringEqualitySanitizer() { this = "string equality sanitizer" } + + /* The test `if untrusted == "KNOWN_VALUE":` sanitizes `untrusted` on its `true` edge. */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + taint instanceof StringKind and + exists(ControlFlowNode const, Cmpop op | const.getNode() instanceof StrConst | + ( + test.getTest().(CompareNode).operands(const, op, _) + or + test.getTest().(CompareNode).operands(_, op, const) + ) and + ( + op instanceof Eq and test.getSense() = true + or + op instanceof NotEq and test.getSense() = false + ) + ) + } +} + +/** tonode = ....format(fromnode) */ +deprecated private predicate str_format(ControlFlowNode fromnode, CallNode tonode) { + tonode.getFunction().(AttrNode).getName() = "format" and + tonode.getAnArg() = fromnode +} + +/** tonode = codec.[en|de]code(fromnode) */ +deprecated private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) { + exists(FunctionObject func, string name | + not func.getFunction().isMethod() and + func.getACall() = tonode and + tonode.getAnArg() = fromnode and + func.getName() = name + | + name = "encode" or + name = "decode" or + name = "decodestring" + ) +} + +/** tonode = str(fromnode) */ +deprecated private predicate to_str(ControlFlowNode fromnode, CallNode tonode) { + tonode.getAnArg() = fromnode and + ( + tonode = ClassValue::bytes().getACall() + or + tonode = ClassValue::unicode().getACall() + ) +} + +/** tonode = fromnode[:] */ +deprecated private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) { + exists(Slice all | + all = tonode.getIndex().getNode() and + not exists(all.getStart()) and + not exists(all.getStop()) and + tonode.getObject() = fromnode + ) +} + +/** tonode = os.path.join(..., fromnode, ...) */ +deprecated private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) { + tonode = Value::named("os.path.join").getACall() and + tonode.getAnArg() = fromnode +} + +/** tonode = f"... {fromnode} ..." */ +deprecated private predicate f_string(ControlFlowNode fromnode, ControlFlowNode tonode) { + tonode.getNode().(Fstring).getAValue() = fromnode.getNode() +} + +/** + * A kind of "taint", representing a dictionary mapping str->"taint" + * + * DEPRECATED: Use `ExternalStringDictKind` instead. + */ +deprecated class StringDictKind extends DictKind { + StringDictKind() { this.getValue() instanceof StringKind } +} diff --git a/python/ql/lib/semmle/python/security/strings/Common.qll b/python/ql/lib/semmle/python/security/strings/Common.qll new file mode 100644 index 00000000000..cb19fdd5461 --- /dev/null +++ b/python/ql/lib/semmle/python/security/strings/Common.qll @@ -0,0 +1,14 @@ +import python + +/** A call that returns a copy (or similar) of the argument */ +deprecated predicate copy_call(ControlFlowNode fromnode, CallNode tonode) { + tonode.getFunction().(AttrNode).getObject("copy") = fromnode + or + exists(ModuleValue copy, string name | name = "copy" or name = "deepcopy" | + copy.attr(name).(FunctionValue).getACall() = tonode and + tonode.getArg(0) = fromnode + ) + or + tonode.getFunction().pointsTo(Value::named("reversed")) and + tonode.getArg(0) = fromnode +} diff --git a/python/ql/lib/semmle/python/security/strings/External.qll b/python/ql/lib/semmle/python/security/strings/External.qll new file mode 100644 index 00000000000..a5116e42e4e --- /dev/null +++ b/python/ql/lib/semmle/python/security/strings/External.qll @@ -0,0 +1,318 @@ +import python +import Basic +private import Common + +/** + * An extensible kind of taint representing an externally controlled string. + */ +abstract deprecated class ExternalStringKind extends StringKind { + bindingset[this] + ExternalStringKind() { this = this } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + result = StringKind.super.getTaintForFlowStep(fromnode, tonode) + or + tonode.(SequenceNode).getElement(_) = fromnode and + result.(ExternalStringSequenceKind).getItem() = this + or + json_load(fromnode, tonode) and result.(ExternalJsonKind).getValue() = this + or + tonode.(DictNode).getAValue() = fromnode and result.(ExternalStringDictKind).getValue() = this + or + urlsplit(fromnode, tonode) and result.(ExternalUrlSplitResult).getItem() = this + or + urlparse(fromnode, tonode) and result.(ExternalUrlParseResult).getItem() = this + or + parse_qs(fromnode, tonode) and result.(ExternalStringDictKind).getValue() = this + or + parse_qsl(fromnode, tonode) and result.(SequenceKind).getItem().(SequenceKind).getItem() = this + } +} + +/** A kind of "taint", representing a sequence, with a "taint" member */ +deprecated class ExternalStringSequenceKind extends SequenceKind { + ExternalStringSequenceKind() { this.getItem() instanceof ExternalStringKind } +} + +/** + * An hierarchical dictionary or list where the entire structure is externally controlled + * This is typically a parsed JSON object. + */ +deprecated class ExternalJsonKind extends TaintKind { + ExternalJsonKind() { this = "json[" + any(ExternalStringKind key) + "]" } + + /** Gets the taint kind for item in this sequence */ + TaintKind getValue() { + this = "json[" + result + "]" + or + result = this + } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + this.taints(fromnode) and + json_subscript_taint(tonode, fromnode, this, result) + or + result = this and copy_call(fromnode, tonode) + } + + override TaintKind getTaintOfMethodResult(string name) { + name = "get" and result = this.getValue() + } +} + +/** A kind of "taint", representing a dictionary mapping keys to tainted strings. */ +deprecated class ExternalStringDictKind extends DictKind { + ExternalStringDictKind() { this.getValue() instanceof ExternalStringKind } +} + +/** + * A kind of "taint", representing a dictionary mapping keys to sequences of + * tainted strings. + */ +deprecated class ExternalStringSequenceDictKind extends DictKind { + ExternalStringSequenceDictKind() { this.getValue() instanceof ExternalStringSequenceKind } +} + +/** TaintKind for the result of `urlsplit(tainted_string)` */ +deprecated class ExternalUrlSplitResult extends ExternalStringSequenceKind { + // https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlsplit + override TaintKind getTaintOfAttribute(string name) { + result = super.getTaintOfAttribute(name) + or + name in [ + // namedtuple field names + "scheme", "netloc", "path", "query", "fragment", + // class methods + "password", "username", "hostname", + ] and + result instanceof ExternalStringKind + } + + override TaintKind getTaintOfMethodResult(string name) { + result = super.getTaintOfMethodResult(name) + or + name = "geturl" and + result instanceof ExternalStringKind + } +} + +/** TaintKind for the result of `urlparse(tainted_string)` */ +deprecated class ExternalUrlParseResult extends ExternalStringSequenceKind { + // https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlparse + override TaintKind getTaintOfAttribute(string name) { + result = super.getTaintOfAttribute(name) + or + name in [ + // namedtuple field names + "scheme", "netloc", "path", "params", "query", "fragment", + // class methods + "username", "password", "hostname", + ] and + result instanceof ExternalStringKind + } + + override TaintKind getTaintOfMethodResult(string name) { + result = super.getTaintOfMethodResult(name) + or + name = "geturl" and + result instanceof ExternalStringKind + } +} + +/* Helper for getTaintForStep() */ +pragma[noinline] +deprecated private predicate json_subscript_taint( + SubscriptNode sub, ControlFlowNode obj, ExternalJsonKind seq, TaintKind key +) { + sub.isLoad() and + sub.getObject() = obj and + key = seq.getValue() +} + +deprecated private predicate json_load(ControlFlowNode fromnode, CallNode tonode) { + tonode = Value::named("json.loads").getACall() and + tonode.getArg(0) = fromnode +} + +deprecated private predicate urlsplit(ControlFlowNode fromnode, CallNode tonode) { + // This could be implemented as `exists(FunctionValue` without the explicit six part, + // but then our tests will need to import +100 modules, so for now this slightly + // altered version gets to live on. + exists(Value urlsplit | + ( + urlsplit = Value::named("six.moves.urllib.parse.urlsplit") + or + // Python 2 + urlsplit = Value::named("urlparse.urlsplit") + or + // Python 3 + urlsplit = Value::named("urllib.parse.urlsplit") + ) and + tonode = urlsplit.getACall() and + tonode.getArg(0) = fromnode + ) +} + +deprecated private predicate urlparse(ControlFlowNode fromnode, CallNode tonode) { + // This could be implemented as `exists(FunctionValue` without the explicit six part, + // but then our tests will need to import +100 modules, so for now this slightly + // altered version gets to live on. + exists(Value urlparse | + ( + urlparse = Value::named("six.moves.urllib.parse.urlparse") + or + // Python 2 + urlparse = Value::named("urlparse.urlparse") + or + // Python 3 + urlparse = Value::named("urllib.parse.urlparse") + ) and + tonode = urlparse.getACall() and + tonode.getArg(0) = fromnode + ) +} + +deprecated private predicate parse_qs(ControlFlowNode fromnode, CallNode tonode) { + // This could be implemented as `exists(FunctionValue` without the explicit six part, + // but then our tests will need to import +100 modules, so for now this slightly + // altered version gets to live on. + exists(Value parse_qs | + ( + parse_qs = Value::named("six.moves.urllib.parse.parse_qs") + or + // Python 2 + parse_qs = Value::named("urlparse.parse_qs") + or + // Python 2 deprecated version of `urlparse.parse_qs` + parse_qs = Value::named("cgi.parse_qs") + or + // Python 3 + parse_qs = Value::named("urllib.parse.parse_qs") + ) and + tonode = parse_qs.getACall() and + ( + tonode.getArg(0) = fromnode + or + tonode.getArgByName("qs") = fromnode + ) + ) +} + +deprecated private predicate parse_qsl(ControlFlowNode fromnode, CallNode tonode) { + // This could be implemented as `exists(FunctionValue` without the explicit six part, + // but then our tests will need to import +100 modules, so for now this slightly + // altered version gets to live on. + exists(Value parse_qsl | + ( + parse_qsl = Value::named("six.moves.urllib.parse.parse_qsl") + or + // Python 2 + parse_qsl = Value::named("urlparse.parse_qsl") + or + // Python 2 deprecated version of `urlparse.parse_qsl` + parse_qsl = Value::named("cgi.parse_qsl") + or + // Python 3 + parse_qsl = Value::named("urllib.parse.parse_qsl") + ) and + tonode = parse_qsl.getACall() and + ( + tonode.getArg(0) = fromnode + or + tonode.getArgByName("qs") = fromnode + ) + ) +} + +/** A kind of "taint", representing an open file-like object from an external source. */ +deprecated class ExternalFileObject extends TaintKind { + ExternalStringKind valueKind; + + ExternalFileObject() { this = "file[" + valueKind + "]" } + + /** Gets the taint kind for the contents of this file */ + TaintKind getValue() { result = valueKind } + + override TaintKind getTaintOfMethodResult(string name) { + name in ["read", "readline"] and result = this.getValue() + or + name = "readlines" and result.(SequenceKind).getItem() = this.getValue() + } + + override TaintKind getTaintForIteration() { result = this.getValue() } +} + +/** + * Temporary sanitizer for the tainted result from `urlsplit` and `urlparse`. Can be used to reduce FPs until + * we have better support for namedtuples. + * + * Will clear **all** taint on a test of the kind. That is, on the true edge of any matching test, + * all fields/indexes will be cleared of taint. + * + * Handles: + * - `if splitres.netloc == "KNOWN_VALUE"` + * - `if splitres[0] == "KNOWN_VALUE"` + */ +deprecated class UrlsplitUrlparseTempSanitizer extends Sanitizer { + // TODO: remove this once we have better support for named tuples + UrlsplitUrlparseTempSanitizer() { this = "UrlsplitUrlparseTempSanitizer" } + + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + ( + taint instanceof ExternalUrlSplitResult + or + taint instanceof ExternalUrlParseResult + ) and + exists(ControlFlowNode full_use | + full_use.(SubscriptNode).getObject() = test.getInput().getAUse() + or + full_use.(AttrNode).getObject() = test.getInput().getAUse() + | + this.clears_taint(full_use, test.getTest(), test.getSense()) + ) + } + + private predicate clears_taint(ControlFlowNode tainted, ControlFlowNode test, boolean sense) { + this.test_equality_with_const(test, tainted, sense) + or + this.test_in_const_seq(test, tainted, sense) + or + test.(UnaryExprNode).getNode().getOp() instanceof Not and + exists(ControlFlowNode nested_test | + nested_test = test.(UnaryExprNode).getOperand() and + this.clears_taint(tainted, nested_test, sense.booleanNot()) + ) + } + + /** holds for `== "KNOWN_VALUE"` on `true` edge, and `!= "KNOWN_VALUE"` on `false` edge */ + private predicate test_equality_with_const(CompareNode cmp, ControlFlowNode tainted, boolean sense) { + exists(ControlFlowNode const, Cmpop op | const.getNode() instanceof StrConst | + ( + cmp.operands(const, op, tainted) + or + cmp.operands(tainted, op, const) + ) and + ( + op instanceof Eq and sense = true + or + op instanceof NotEq and sense = false + ) + ) + } + + /** holds for `in ["KNOWN_VALUE", ...]` on `true` edge, and `not in ["KNOWN_VALUE", ...]` on `false` edge */ + private predicate test_in_const_seq(CompareNode cmp, ControlFlowNode tainted, boolean sense) { + exists(SequenceNode const_seq, Cmpop op | + forall(ControlFlowNode elem | elem = const_seq.getAnElement() | + elem.getNode() instanceof StrConst + ) + | + cmp.operands(tainted, op, const_seq) and + ( + op instanceof In and sense = true + or + op instanceof NotIn and sense = false + ) + ) + } +} diff --git a/python/ql/lib/semmle/python/security/strings/Untrusted.qll b/python/ql/lib/semmle/python/security/strings/Untrusted.qll new file mode 100644 index 00000000000..2916b723a8f --- /dev/null +++ b/python/ql/lib/semmle/python/security/strings/Untrusted.qll @@ -0,0 +1,10 @@ +import python +import External + +/** + * A kind of taint representing an externally controlled string. + * This class is a simple sub-class of `ExternalStringKind`. + */ +deprecated class UntrustedStringKind extends ExternalStringKind { + UntrustedStringKind() { this = "externally controlled string" } +} diff --git a/python/ql/lib/semmle/python/web/Http.qll b/python/ql/lib/semmle/python/web/Http.qll new file mode 100644 index 00000000000..85100e6524e --- /dev/null +++ b/python/ql/lib/semmle/python/web/Http.qll @@ -0,0 +1,119 @@ +import python +import semmle.python.dataflow.Implementation +import semmle.python.security.strings.External +import HttpConstants + +/** Generic taint source from a http request */ +abstract deprecated class HttpRequestTaintSource extends TaintSource { } + +/** + * Taint kind representing the WSGI environment. + * As specified in PEP 3333. https://www.python.org/dev/peps/pep-3333/#environ-variables + */ +deprecated class WsgiEnvironment extends TaintKind { + WsgiEnvironment() { this = "wsgi.environment" } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + result = this and Implementation::copyCall(fromnode, tonode) + or + result = this and + tonode.(CallNode).getFunction().pointsTo(ClassValue::dict()) and + tonode.(CallNode).getArg(0) = fromnode + or + exists(Value key, string text | + tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode and + tonode.(CallNode).getArg(0).pointsTo(key) + or + tonode.(SubscriptNode).getObject() = fromnode and + tonode.isLoad() and + tonode.(SubscriptNode).getIndex().pointsTo(key) + | + key = Value::forString(text) and + result instanceof ExternalStringKind and + ( + text = "QUERY_STRING" or + text = "PATH_INFO" or + text.matches("HTTP\\_%") + ) + ) + } +} + +/** + * A standard morsel object from a HTTP request, a value in a cookie, + * typically an instance of `http.cookies.Morsel` + */ +deprecated class UntrustedMorsel extends TaintKind { + UntrustedMorsel() { this = "http.Morsel" } + + override TaintKind getTaintOfAttribute(string name) { + result instanceof ExternalStringKind and + name = "value" + } +} + +/** A standard cookie object from a HTTP request, typically an instance of `http.cookies.SimpleCookie` */ +deprecated class UntrustedCookie extends TaintKind { + UntrustedCookie() { this = "http.Cookie" } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + tonode.(SubscriptNode).getObject() = fromnode and + result instanceof UntrustedMorsel + } +} + +abstract deprecated class CookieOperation extends @py_flow_node { + /** Gets a textual representation of this element. */ + abstract string toString(); + + abstract ControlFlowNode getKey(); + + abstract ControlFlowNode getValue(); +} + +abstract deprecated class CookieGet extends CookieOperation { } + +abstract deprecated class CookieSet extends CookieOperation { } + +/** Generic taint sink in a http response */ +abstract deprecated class HttpResponseTaintSink extends TaintSink { + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} + +abstract deprecated class HttpRedirectTaintSink extends TaintSink { + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} + +deprecated module Client { + // TODO: user-input in other than URL: + // - `data`, `json` for `requests.post` + // - `body` for `HTTPConnection.request` + // - headers? + // TODO: Add more library support + // - urllib3 https://github.com/urllib3/urllib3 + // - httpx https://github.com/encode/httpx + /** + * An outgoing http request + * + * For example: + * conn = HTTPConnection('example.com') + * conn.request('GET', '/path') + */ + abstract class HttpRequest extends ControlFlowNode { + /** + * Get any ControlFlowNode that is used to construct the final URL. + * + * In the HTTPConnection example, there is a result for both `'example.com'` and for `'/path'`. + */ + abstract ControlFlowNode getAUrlPart(); + + abstract string getMethodUpper(); + } + + /** Taint sink for the URL-part of an outgoing http request */ + class HttpRequestUrlTaintSink extends TaintSink { + HttpRequestUrlTaintSink() { this = any(HttpRequest r).getAUrlPart() } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + } +} diff --git a/python/ql/lib/semmle/python/web/HttpConstants.qll b/python/ql/lib/semmle/python/web/HttpConstants.qll new file mode 100644 index 00000000000..e5cebb57729 --- /dev/null +++ b/python/ql/lib/semmle/python/web/HttpConstants.qll @@ -0,0 +1,7 @@ +/** Gets an HTTP verb, in upper case */ +deprecated string httpVerb() { + result in ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"] +} + +/** Gets an HTTP verb, in lower case */ +deprecated string httpVerbLower() { result = httpVerb().toLowerCase() } diff --git a/python/ql/lib/semmle/python/web/HttpRequest.qll b/python/ql/lib/semmle/python/web/HttpRequest.qll new file mode 100644 index 00000000000..88dd36049b4 --- /dev/null +++ b/python/ql/lib/semmle/python/web/HttpRequest.qll @@ -0,0 +1,10 @@ +import semmle.python.web.django.Request +import semmle.python.web.flask.Request +import semmle.python.web.tornado.Request +import semmle.python.web.pyramid.Request +import semmle.python.web.twisted.Request +import semmle.python.web.bottle.Request +import semmle.python.web.turbogears.Request +import semmle.python.web.falcon.Request +import semmle.python.web.cherrypy.Request +import semmle.python.web.stdlib.Request diff --git a/python/ql/lib/semmle/python/web/bottle/General.qll b/python/ql/lib/semmle/python/web/bottle/General.qll new file mode 100644 index 00000000000..cbb42c97305 --- /dev/null +++ b/python/ql/lib/semmle/python/web/bottle/General.qll @@ -0,0 +1,46 @@ +import python +import semmle.python.web.Http +import semmle.python.types.Extensions + +/** Gets the bottle module */ +deprecated ModuleValue theBottleModule() { result = Module::named("bottle") } + +/** Gets the bottle.Bottle class */ +deprecated ClassValue theBottleClass() { result = theBottleModule().attr("Bottle") } + +/** + * Holds if `route` is routed to `func` + * by decorating `func` with `app.route(route)` or `route(route)` + */ +deprecated predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func) { + exists(CallNode decorator_call, string name | + route_call.getFunction().(AttrNode).getObject(name).pointsTo().getClass() = theBottleClass() or + route_call.getFunction().pointsTo(theBottleModule().attr(name)) + | + (name = "route" or name = httpVerbLower()) and + decorator_call.getFunction() = route_call and + route_call.getArg(0) = route and + decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func + ) +} + +deprecated class BottleRoute extends ControlFlowNode { + BottleRoute() { bottle_route(this, _, _) } + + string getUrl() { + exists(StrConst url | + bottle_route(this, url.getAFlowNode(), _) and + result = url.getText() + ) + } + + Function getFunction() { bottle_route(this, _, result) } + + Parameter getANamedArgument() { + exists(string name, Function func | + func = this.getFunction() and + func.getArgByName(name) = result and + this.getUrl().matches("%<" + name + ">%") + ) + } +} diff --git a/python/ql/lib/semmle/python/web/bottle/Request.qll b/python/ql/lib/semmle/python/web/bottle/Request.qll new file mode 100644 index 00000000000..3de4748b30e --- /dev/null +++ b/python/ql/lib/semmle/python/web/bottle/Request.qll @@ -0,0 +1,80 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.security.strings.External +import semmle.python.web.Http +import semmle.python.web.bottle.General + +deprecated private Value theBottleRequestObject() { result = theBottleModule().attr("request") } + +deprecated class BottleRequestKind extends TaintKind { + BottleRequestKind() { this = "bottle.request" } + + override TaintKind getTaintOfAttribute(string name) { + result instanceof BottleFormsDict and + (name = "cookies" or name = "query" or name = "form") + or + result instanceof ExternalStringKind and + (name = "query_string" or name = "url_args") + or + result.(DictKind).getValue() instanceof FileUpload and + name = "files" + } +} + +deprecated private class RequestSource extends HttpRequestTaintSource { + RequestSource() { this.(ControlFlowNode).pointsTo(theBottleRequestObject()) } + + override predicate isSourceOf(TaintKind kind) { kind instanceof BottleRequestKind } +} + +deprecated class BottleFormsDict extends TaintKind { + BottleFormsDict() { this = "bottle.FormsDict" } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + /* Cannot use `getTaintOfAttribute(name)` as it wouldn't bind `name` */ + exists(string name | + fromnode = tonode.(AttrNode).getObject(name) and + result instanceof ExternalStringKind + | + name != "get" and name != "getunicode" and name != "getall" + ) + } + + override TaintKind getTaintOfMethodResult(string name) { + (name = "get" or name = "getunicode") and + result instanceof ExternalStringKind + or + name = "getall" and result.(SequenceKind).getItem() instanceof ExternalStringKind + } +} + +deprecated class FileUpload extends TaintKind { + FileUpload() { this = "bottle.FileUpload" } + + override TaintKind getTaintOfAttribute(string name) { + name = "filename" and result instanceof ExternalStringKind + or + name = "raw_filename" and result instanceof ExternalStringKind + or + name = "file" and result instanceof UntrustedFile + } +} + +deprecated class UntrustedFile extends TaintKind { + UntrustedFile() { this = "Untrusted file" } +} + +// +// TO DO.. File uploads -- Should check about file uploads for other frameworks as well. +// Move UntrustedFile to shared location +// +/** A parameter to a bottle request handler function */ +deprecated class BottleRequestParameter extends HttpRequestTaintSource { + BottleRequestParameter() { + exists(BottleRoute route | route.getANamedArgument() = this.(ControlFlowNode).getNode()) + } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + + override string toString() { result = "bottle handler function argument" } +} diff --git a/python/ql/lib/semmle/python/web/cherrypy/General.qll b/python/ql/lib/semmle/python/web/cherrypy/General.qll new file mode 100644 index 00000000000..40becc70a50 --- /dev/null +++ b/python/ql/lib/semmle/python/web/cherrypy/General.qll @@ -0,0 +1,44 @@ +import python +import semmle.python.web.Http + +deprecated module CherryPy { + FunctionValue expose() { result = Value::named("cherrypy.expose") } +} + +deprecated class CherryPyExposedFunction extends Function { + CherryPyExposedFunction() { + this.getADecorator().pointsTo(CherryPy::expose()) + or + this.getADecorator().(Call).getFunc().pointsTo(CherryPy::expose()) + } +} + +deprecated class CherryPyRoute extends CallNode { + CherryPyRoute() { + /* cherrypy.quickstart(root, script_name, config) */ + Value::named("cherrypy.quickstart").(FunctionValue).getACall() = this + or + /* cherrypy.tree.mount(root, script_name, config) */ + this.getFunction().(AttrNode).getObject("mount").pointsTo(Value::named("cherrypy.tree")) + } + + ClassValue getAppClass() { + this.getArg(0).pointsTo().getClass() = result + or + this.getArgByName("root").pointsTo().getClass() = result + } + + string getPath() { + exists(Value path | path = Value::forString(result) | + this.getArg(1).pointsTo(path) + or + this.getArgByName("script_name").pointsTo(path) + ) + } + + ClassValue getConfig() { + this.getArg(2).pointsTo().getClass() = result + or + this.getArgByName("config").pointsTo().getClass() = result + } +} diff --git a/python/ql/lib/semmle/python/web/cherrypy/Request.qll b/python/ql/lib/semmle/python/web/cherrypy/Request.qll new file mode 100644 index 00000000000..b3c096f8bdd --- /dev/null +++ b/python/ql/lib/semmle/python/web/cherrypy/Request.qll @@ -0,0 +1,41 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.security.strings.Basic +import semmle.python.web.Http +import semmle.python.web.cherrypy.General + +/** The cherrypy.request local-proxy object */ +deprecated class CherryPyRequest extends TaintKind { + CherryPyRequest() { this = "cherrypy.request" } + + override TaintKind getTaintOfAttribute(string name) { + name = "params" and result instanceof ExternalStringDictKind + or + name = "cookie" and result instanceof UntrustedCookie + } + + override TaintKind getTaintOfMethodResult(string name) { + name in ["getHeader", "getCookie", "getUser", "getPassword"] and + result instanceof ExternalStringKind + } +} + +deprecated class CherryPyExposedFunctionParameter extends HttpRequestTaintSource { + CherryPyExposedFunctionParameter() { + exists(Parameter p | + p = any(CherryPyExposedFunction f).getAnArg() and + not p.isSelf() and + p.asName().getAFlowNode() = this + ) + } + + override string toString() { result = "CherryPy handler function parameter" } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } +} + +deprecated class CherryPyRequestSource extends HttpRequestTaintSource { + CherryPyRequestSource() { this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) } + + override predicate isSourceOf(TaintKind kind) { kind instanceof CherryPyRequest } +} diff --git a/python/ql/lib/semmle/python/web/django/General.qll b/python/ql/lib/semmle/python/web/django/General.qll new file mode 100644 index 00000000000..1b179b35f9a --- /dev/null +++ b/python/ql/lib/semmle/python/web/django/General.qll @@ -0,0 +1,136 @@ +import python +import semmle.python.regex +import semmle.python.web.Http + +// TODO: Since django uses `path = partial(...)`, our analysis doesn't understand this is +// a FunctionValue, so we can't use `FunctionValue.getArgumentForCall` +// https://github.com/django/django/blob/master/django/urls/conf.py#L76 +abstract deprecated class DjangoRoute extends CallNode { + DjangoViewHandler getViewHandler() { + result = view_handler_from_view_arg(this.getArg(1)) + or + result = view_handler_from_view_arg(this.getArgByName("view")) + } + + abstract string getANamedArgument(); + + /** + * Get the number of positional arguments that will be passed to the view. + * Will only return a result if there are no named arguments. + */ + abstract int getNumPositionalArguments(); +} + +/** + * For function based views -- also see `DjangoClassBasedViewHandler` + * https://docs.djangoproject.com/en/1.11/topics/http/views/ + * https://docs.djangoproject.com/en/3.0/topics/http/views/ + */ +deprecated class DjangoViewHandler extends PythonFunctionValue { + /** Gets the index of the 'request' argument */ + int getRequestArgIndex() { result = 0 } +} + +/** + * Class based views + * https://docs.djangoproject.com/en/1.11/topics/class-based-views/ + * https://docs.djangoproject.com/en/3.0/topics/class-based-views/ + */ +deprecated private class DjangoViewClass extends ClassValue { + DjangoViewClass() { + Value::named("django.views.generic.View") = this.getASuperType() + or + Value::named("django.views.View") = this.getASuperType() + } +} + +deprecated class DjangoClassBasedViewHandler extends DjangoViewHandler { + DjangoClassBasedViewHandler() { exists(DjangoViewClass cls | cls.lookup(httpVerbLower()) = this) } + + override int getRequestArgIndex() { + // due to `self` being the first parameter + result = 1 + } +} + +/** + * Gets the function that will handle requests when `view_arg` is used as the view argument to a + * django route. That is, this methods handles Class-based Views and its `as_view()` function. + */ +deprecated private DjangoViewHandler view_handler_from_view_arg(ControlFlowNode view_arg) { + // Function-based view + result = view_arg.pointsTo() + or + // Class-based view + exists(ClassValue cls | + cls = view_arg.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo() and + result = cls.lookup(httpVerbLower()) + ) +} + +// We need this "dummy" class, since otherwise the regex argument would not be considered +// a regex (RegexString is abstract) +deprecated class DjangoRouteRegex extends RegexString { + DjangoRouteRegex() { exists(DjangoRegexRoute route | route.getRouteArg() = this.getAFlowNode()) } +} + +deprecated class DjangoRegexRoute extends DjangoRoute { + ControlFlowNode route; + + DjangoRegexRoute() { + exists(FunctionValue route_maker | + // Django 1.x: https://docs.djangoproject.com/en/1.11/ref/urls/#django.conf.urls.url + Value::named("django.conf.urls.url") = route_maker and + route_maker.getArgumentForCall(this, 0) = route + ) + or + // Django 2.x and 3.x: https://docs.djangoproject.com/en/3.0/ref/urls/#re-path + this = Value::named("django.urls.re_path").getACall() and + ( + route = this.getArg(0) + or + route = this.getArgByName("route") + ) + } + + ControlFlowNode getRouteArg() { result = route } + + override string getANamedArgument() { + exists(DjangoRouteRegex regex | regex.getAFlowNode() = route | + result = regex.getGroupName(_, _) + ) + } + + override int getNumPositionalArguments() { + not exists(this.getANamedArgument()) and + exists(DjangoRouteRegex regex | regex.getAFlowNode() = route | + result = count(regex.getGroupNumber(_, _)) + ) + } +} + +deprecated class DjangoPathRoute extends DjangoRoute { + ControlFlowNode route; + + DjangoPathRoute() { + // Django 2.x and 3.x: https://docs.djangoproject.com/en/3.0/ref/urls/#path + this = Value::named("django.urls.path").getACall() and + ( + route = this.getArg(0) + or + route = this.getArgByName("route") + ) + } + + override string getANamedArgument() { + // regexp taken from django: + // https://github.com/django/django/blob/7d1bf29977bb368d7c28e7c6eb146db3b3009ae7/django/urls/resolvers.py#L199 + exists(StrConst route_str, string match | + route_str = route.getNode() and + match = route_str.getText().regexpFind("<(?:(?[^>:]+):)?(?\\w+)>", _, _) and + result = match.regexpCapture("<(?:(?[^>:]+):)?(?\\w+)>", 2) + ) + } + + override int getNumPositionalArguments() { none() } +} diff --git a/python/ql/lib/semmle/python/web/django/Request.qll b/python/ql/lib/semmle/python/web/django/Request.qll new file mode 100644 index 00000000000..7e7358595e5 --- /dev/null +++ b/python/ql/lib/semmle/python/web/django/Request.qll @@ -0,0 +1,78 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.web.Http +import semmle.python.web.django.General + +/** A django.request.HttpRequest object */ +deprecated class DjangoRequest extends TaintKind { + DjangoRequest() { this = "django.request.HttpRequest" } + + override TaintKind getTaintOfAttribute(string name) { + (name = "GET" or name = "POST") and + result instanceof DjangoQueryDict + } + + override TaintKind getTaintOfMethodResult(string name) { + (name = "body" or name = "path") and + result instanceof ExternalStringKind + } +} + +/* Helper for getTaintForStep() */ +pragma[noinline] +deprecated private predicate subscript_taint(SubscriptNode sub, ControlFlowNode obj, TaintKind kind) { + sub.getObject() = obj and + kind instanceof ExternalStringKind +} + +/** A django.request.QueryDict object */ +deprecated class DjangoQueryDict extends TaintKind { + DjangoQueryDict() { this = "django.http.request.QueryDict" } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + this.taints(fromnode) and + subscript_taint(tonode, fromnode, result) + } + + override TaintKind getTaintOfMethodResult(string name) { + name = "get" and result instanceof ExternalStringKind + } +} + +/** A Django request parameter */ +deprecated class DjangoRequestSource extends HttpRequestTaintSource { + DjangoRequestSource() { + exists(DjangoRoute route, DjangoViewHandler view, int request_arg_index | + route.getViewHandler() = view and + request_arg_index = view.getRequestArgIndex() and + this = view.getScope().getArg(request_arg_index).asName().getAFlowNode() + ) + } + + override string toString() { result = "Django request source" } + + override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoRequest } +} + +/** An argument specified in a url routing table */ +deprecated class DjangoRequestParameter extends HttpRequestTaintSource { + DjangoRequestParameter() { + exists(DjangoRoute route, Function f, DjangoViewHandler view, int request_arg_index | + route.getViewHandler() = view and + request_arg_index = view.getRequestArgIndex() and + f = view.getScope() + | + this.(ControlFlowNode).getNode() = f.getArgByName(route.getANamedArgument()) + or + exists(int i | i >= 0 | + i < route.getNumPositionalArguments() and + // +1 because first argument is always the request + this.(ControlFlowNode).getNode() = f.getArg(request_arg_index + 1 + i) + ) + ) + } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + + override string toString() { result = "django.http.request.parameter" } +} diff --git a/python/ql/lib/semmle/python/web/falcon/General.qll b/python/ql/lib/semmle/python/web/falcon/General.qll new file mode 100644 index 00000000000..5f9cce57611 --- /dev/null +++ b/python/ql/lib/semmle/python/web/falcon/General.qll @@ -0,0 +1,46 @@ +import python +import semmle.python.web.Http + +/** Gets the falcon API class */ +deprecated ClassValue theFalconAPIClass() { result = Value::named("falcon.API") } + +/** Holds if `route` is routed to `resource` */ +deprecated private predicate api_route( + CallNode route_call, ControlFlowNode route, ClassValue resource +) { + route_call.getFunction().(AttrNode).getObject("add_route").pointsTo().getClass() = + theFalconAPIClass() and + route_call.getArg(0) = route and + route_call.getArg(1).pointsTo().getClass() = resource +} + +deprecated private predicate route(FalconRoute route, Function target, string funcname) { + route.getResourceClass().lookup("on_" + funcname).(FunctionValue).getScope() = target +} + +deprecated class FalconRoute extends ControlFlowNode { + FalconRoute() { api_route(this, _, _) } + + string getUrl() { + exists(StrConst url | + api_route(this, url.getAFlowNode(), _) and + result = url.getText() + ) + } + + ClassValue getResourceClass() { api_route(this, _, result) } + + FalconHandlerFunction getHandlerFunction(string method) { route(this, result, method) } +} + +deprecated class FalconHandlerFunction extends Function { + FalconHandlerFunction() { route(_, this, _) } + + private string methodName() { route(_, this, result) } + + string getMethod() { result = this.methodName().toUpperCase() } + + Parameter getRequest() { result = this.getArg(1) } + + Parameter getResponse() { result = this.getArg(2) } +} diff --git a/python/ql/lib/semmle/python/web/falcon/Request.qll b/python/ql/lib/semmle/python/web/falcon/Request.qll new file mode 100644 index 00000000000..ac4c92f3ad0 --- /dev/null +++ b/python/ql/lib/semmle/python/web/falcon/Request.qll @@ -0,0 +1,37 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.web.Http +import semmle.python.web.falcon.General + +/** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */ +deprecated class FalconRequest extends TaintKind { + FalconRequest() { this = "falcon.request" } + + override TaintKind getTaintOfAttribute(string name) { + name = "env" and result instanceof WsgiEnvironment + or + result instanceof ExternalStringKind and + name in ["uri", "url", "forwarded_uri", "relative_uri", "query_string"] + or + result instanceof ExternalStringDictKind and + (name = "cookies" or name = "params") + or + name = "stream" and result instanceof ExternalFileObject + } + + override TaintKind getTaintOfMethodResult(string name) { + name = "get_param" and result instanceof ExternalStringKind + or + name = "get_param_as_json" and result instanceof ExternalJsonKind + or + name = "get_param_as_list" and result instanceof ExternalStringSequenceKind + } +} + +deprecated class FalconRequestParameter extends HttpRequestTaintSource { + FalconRequestParameter() { + exists(FalconHandlerFunction f | f.getRequest() = this.(ControlFlowNode).getNode()) + } + + override predicate isSourceOf(TaintKind k) { k instanceof FalconRequest } +} diff --git a/python/ql/lib/semmle/python/web/flask/General.qll b/python/ql/lib/semmle/python/web/flask/General.qll new file mode 100644 index 00000000000..cc4d992f9ff --- /dev/null +++ b/python/ql/lib/semmle/python/web/flask/General.qll @@ -0,0 +1,104 @@ +import python +import semmle.python.web.Http +import semmle.python.web.flask.Response + +/** Gets the flask app class */ +deprecated ClassValue theFlaskClass() { result = Value::named("flask.Flask") } + +/** Gets the flask MethodView class */ +deprecated ClassValue theFlaskMethodViewClass() { result = Value::named("flask.views.MethodView") } + +deprecated ClassValue theFlaskReponseClass() { result = Value::named("flask.Response") } + +/** + * Holds if `route` is routed to `func` + * by decorating `func` with `app.route(route)` + */ +deprecated predicate app_route(ControlFlowNode route, Function func) { + exists(CallNode route_call, CallNode decorator_call | + route_call.getFunction().(AttrNode).getObject("route").pointsTo().getClass() = theFlaskClass() and + decorator_call.getFunction() = route_call and + route_call.getArg(0) = route and + decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func + ) +} + +/* Helper for add_url_rule */ +deprecated private predicate add_url_rule_call(ControlFlowNode regex, ControlFlowNode callable) { + exists(CallNode call | + call.getFunction().(AttrNode).getObject("add_url_rule").pointsTo().getClass() = theFlaskClass() and + regex = call.getArg(0) + | + callable = call.getArg(2) or + callable = call.getArgByName("view_func") + ) +} + +/** Holds if urls matching `regex` are routed to `func` */ +deprecated predicate add_url_rule(ControlFlowNode regex, Function func) { + exists(ControlFlowNode callable | add_url_rule_call(regex, callable) | + exists(PythonFunctionValue f | f.getScope() = func and callable.pointsTo(f)) + or + /* MethodView.as_view() */ + exists(MethodViewClass view_cls | view_cls.asTaint().taints(callable) | + func = view_cls.lookup(httpVerbLower()).(FunctionValue).getScope() + ) + /* TODO: -- Handle Views that aren't MethodViews */ + ) +} + +/** + * Holds if urls matching `regex` are routed to `func` using + * any of flask's routing mechanisms. + */ +deprecated predicate flask_routing(ControlFlowNode regex, Function func) { + app_route(regex, func) + or + add_url_rule(regex, func) +} + +/** A class that extends flask.views.MethodView */ +deprecated private class MethodViewClass extends ClassValue { + MethodViewClass() { this.getASuperType() = theFlaskMethodViewClass() } + + /* As we are restricted to strings for taint kinds, we need to map these classes to strings. */ + string taintString() { result = "flask/" + this.getQualifiedName() + ".as.view" } + + /* As we are restricted to strings for taint kinds, we need to map these classes to strings. */ + TaintKind asTaint() { result = this.taintString() } +} + +deprecated private class MethodViewTaint extends TaintKind { + MethodViewTaint() { any(MethodViewClass cls).taintString() = this } +} + +/** A source of method view "taint"s. */ +deprecated private class AsView extends TaintSource { + AsView() { + exists(ClassValue view_class | + view_class.getASuperType() = theFlaskMethodViewClass() and + this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class) + ) + } + + override string toString() { result = "flask.MethodView.as_view()" } + + override predicate isSourceOf(TaintKind kind) { + exists(MethodViewClass view_class | + kind = view_class.asTaint() and + this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class) + ) + } +} + +deprecated class FlaskCookieSet extends CookieSet, CallNode { + FlaskCookieSet() { + any(FlaskResponseTaintKind t).taints(this.getFunction().(AttrNode).getObject("set_cookie")) + } + + override string toString() { result = CallNode.super.toString() } + + override ControlFlowNode getKey() { result = this.getArg(0) } + + override ControlFlowNode getValue() { result = this.getArg(1) } +} diff --git a/python/ql/lib/semmle/python/web/flask/Request.qll b/python/ql/lib/semmle/python/web/flask/Request.qll new file mode 100644 index 00000000000..ea9a59dc45e --- /dev/null +++ b/python/ql/lib/semmle/python/web/flask/Request.qll @@ -0,0 +1,80 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.web.Http +import semmle.python.web.flask.General + +deprecated private Value theFlaskRequestObject() { result = Value::named("flask.request") } + +/** Holds if `attr` is an access of attribute `name` of the flask request object */ +deprecated private predicate flask_request_attr(AttrNode attr, string name) { + attr.isLoad() and + attr.getObject(name).pointsTo(theFlaskRequestObject()) +} + +/** Source of external data from a flask request */ +deprecated class FlaskRequestData extends HttpRequestTaintSource { + FlaskRequestData() { + not this instanceof FlaskRequestArgs and + exists(string name | flask_request_attr(this, name) | + name in ["path", "full_path", "base_url", "url"] + ) + } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + + override string toString() { result = "flask.request" } +} + +/** Source of dictionary whose values are externally controlled */ +deprecated class FlaskRequestArgs extends HttpRequestTaintSource { + FlaskRequestArgs() { + exists(string attr | flask_request_attr(this, attr) | + attr in ["args", "form", "values", "files", "headers", "json"] + ) + } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } + + override string toString() { result = "flask.request.args" } +} + +/** Source of dictionary whose values are externally controlled */ +deprecated class FlaskRequestJson extends HttpRequestTaintSource { + FlaskRequestJson() { flask_request_attr(this, "json") } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalJsonKind } + + override string toString() { result = "flask.request.json" } +} + +/** + * A parameter to a flask request handler, that can capture a part of the URL (as specified in + * the url-pattern of a route). + * + * For example, the `name` parameter in: + * ``` + * @app.route('/hello/') + * def hello(name): + * ``` + */ +deprecated class FlaskRoutedParameter extends HttpRequestTaintSource { + FlaskRoutedParameter() { + exists(string name, Function func, StrConst url_pattern | + this.(ControlFlowNode).getNode() = func.getArgByName(name) and + flask_routing(url_pattern.getAFlowNode(), func) and + exists(string match | + match = url_pattern.getS().regexpFind(werkzeug_rule_re(), _, _) and + name = match.regexpCapture(werkzeug_rule_re(), 4) + ) + ) + } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } +} + +deprecated private string werkzeug_rule_re() { + // since flask uses werkzeug internally, we are using its routing rules from + // https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151 + result = + "(?[^<]*)<(?:(?[a-zA-Z_][a-zA-Z0-9_]*)(?:\\((?.*?)\\))?\\:)?(?[a-zA-Z_][a-zA-Z0-9_]*)>" +} diff --git a/python/ql/lib/semmle/python/web/flask/Response.qll b/python/ql/lib/semmle/python/web/flask/Response.qll new file mode 100644 index 00000000000..1e489c56b46 --- /dev/null +++ b/python/ql/lib/semmle/python/web/flask/Response.qll @@ -0,0 +1,55 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.security.strings.Basic +import semmle.python.web.flask.General + +/** + * A flask response, which is vulnerable to any sort of + * http response malice. + */ +deprecated class FlaskRoutedResponse extends HttpResponseTaintSink { + FlaskRoutedResponse() { + exists(PythonFunctionValue response | + flask_routing(_, response.getScope()) and + this = response.getAReturnedNode() + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof StringKind } + + override string toString() { result = "flask.routed.response" } +} + +deprecated class FlaskResponseArgument extends HttpResponseTaintSink { + FlaskResponseArgument() { + exists(CallNode call | + ( + call.getFunction().pointsTo(theFlaskReponseClass()) + or + call.getFunction().pointsTo(Value::named("flask.make_response")) + ) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof StringKind } + + override string toString() { result = "flask.response.argument" } +} + +deprecated class FlaskResponseTaintKind extends TaintKind { + FlaskResponseTaintKind() { this = "flask.Response" } +} + +deprecated class FlaskResponseConfiguration extends TaintTracking::Configuration { + FlaskResponseConfiguration() { this = "Flask response configuration" } + + override predicate isSource(DataFlow::Node node, TaintKind kind) { + kind instanceof FlaskResponseTaintKind and + ( + node.asCfgNode().(CallNode).getFunction().pointsTo(theFlaskReponseClass()) + or + node.asCfgNode().(CallNode).getFunction().pointsTo(Value::named("flask.make_response")) + ) + } +} diff --git a/python/ql/lib/semmle/python/web/pyramid/Request.qll b/python/ql/lib/semmle/python/web/pyramid/Request.qll new file mode 100644 index 00000000000..df84cc84440 --- /dev/null +++ b/python/ql/lib/semmle/python/web/pyramid/Request.qll @@ -0,0 +1,25 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.web.Http +private import semmle.python.web.webob.Request +private import semmle.python.web.pyramid.View + +deprecated class PyramidRequest extends BaseWebobRequest { + PyramidRequest() { this = "pyramid.request" } + + override ClassValue getType() { result = Value::named("pyramid.request.Request") } +} + +/** Source of pyramid request objects */ +deprecated class PyramidViewArgument extends HttpRequestTaintSource { + PyramidViewArgument() { + exists(Function view_func | + is_pyramid_view_function(view_func) and + this.(ControlFlowNode).getNode() = view_func.getArg(0) + ) + } + + override predicate isSourceOf(TaintKind kind) { kind instanceof PyramidRequest } + + override string toString() { result = "pyramid.view.argument" } +} diff --git a/python/ql/lib/semmle/python/web/pyramid/View.qll b/python/ql/lib/semmle/python/web/pyramid/View.qll new file mode 100644 index 00000000000..37d9334cb07 --- /dev/null +++ b/python/ql/lib/semmle/python/web/pyramid/View.qll @@ -0,0 +1,9 @@ +import python + +deprecated ModuleValue thePyramidViewModule() { result.getName() = "pyramid.view" } + +deprecated Value thePyramidViewConfig() { result = thePyramidViewModule().attr("view_config") } + +deprecated predicate is_pyramid_view_function(Function func) { + func.getADecorator().pointsTo().getClass() = thePyramidViewConfig() +} diff --git a/python/ql/lib/semmle/python/web/stdlib/Request.qll b/python/ql/lib/semmle/python/web/stdlib/Request.qll new file mode 100644 index 00000000000..ff850233616 --- /dev/null +++ b/python/ql/lib/semmle/python/web/stdlib/Request.qll @@ -0,0 +1,126 @@ +/** + * Provides the sources and taint-flow for HTTP servers defined using the standard library (stdlib). + * Specifically, we model `HttpRequestTaintSource`s from instances of `BaseHTTPRequestHandler` + * (or subclasses) and form parsing using `cgi.FieldStorage`. + */ + +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.web.Http + +/** Source of BaseHttpRequestHandler instances. */ +deprecated class StdLibRequestSource extends HttpRequestTaintSource { + StdLibRequestSource() { + exists(ClassValue cls | + cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler") + or + cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler") + | + this.(ControlFlowNode).pointsTo().getClass() = cls + ) + } + + override predicate isSourceOf(TaintKind kind) { kind instanceof BaseHTTPRequestHandlerKind } +} + +/** TaintKind for an instance of BaseHttpRequestHandler. */ +deprecated class BaseHTTPRequestHandlerKind extends TaintKind { + BaseHTTPRequestHandlerKind() { this = "BaseHTTPRequestHandlerKind" } + + override TaintKind getTaintOfAttribute(string name) { + name in ["requestline", "path"] and + result instanceof ExternalStringKind + or + name = "headers" and + result instanceof HTTPMessageKind + or + name = "rfile" and + result instanceof ExternalFileObject + } +} + +/** TaintKind for headers (instance of HttpMessage). */ +deprecated class HTTPMessageKind extends ExternalStringDictKind { + override TaintKind getTaintOfMethodResult(string name) { + result = super.getTaintOfMethodResult(name) + or + name = "get_all" and + result.(SequenceKind).getItem() = this.getValue() + or + name in ["as_bytes", "as_string"] and + result instanceof ExternalStringKind + } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + result = super.getTaintForFlowStep(fromnode, tonode) + or + exists(ClassValue cls | cls = ClassValue::unicode() or cls = ClassValue::bytes() | + tonode = cls.getACall() and + tonode.(CallNode).getArg(0) = fromnode and + result instanceof ExternalStringKind + ) + } +} + +/** Source of parsed HTTP forms (by using the `cgi` module). */ +deprecated class CgiFieldStorageSource extends HttpRequestTaintSource { + CgiFieldStorageSource() { this = Value::named("cgi.FieldStorage").getACall() } + + override predicate isSourceOf(TaintKind kind) { kind instanceof CgiFieldStorageFormKind } +} + +/** TaintKind for a parsed HTTP form. */ +deprecated class CgiFieldStorageFormKind extends TaintKind { + /* + * There is a slight difference between how we model form/fields and how it is handled by the code. + * In the code + * ``` + * form = cgi.FieldStorage() + * field = form['myfield'] + * ``` + * both `form` and `field` have the type `cgi.FieldStorage`. This allows the code to represent + * nested forms as `form['nested_form']['myfield']`. However, since HTML forms can't be nested + * we ignore that detail since it allows for a more clean modeling. + */ + + CgiFieldStorageFormKind() { this = "CgiFieldStorageFormKind" } + + override TaintKind getTaintOfAttribute(string name) { + name = "value" and result.(SequenceKind).getItem() instanceof CgiFieldStorageFieldKind + } + + override TaintKind getTaintOfMethodResult(string name) { + name = "getvalue" and + ( + result instanceof ExternalStringKind + or + result.(SequenceKind).getItem() instanceof ExternalStringKind + ) + or + name = "getfirst" and + result instanceof ExternalStringKind + or + name = "getlist" and + result.(SequenceKind).getItem() instanceof ExternalStringKind + } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + tonode.(SubscriptNode).getObject() = fromnode and + ( + result instanceof CgiFieldStorageFieldKind + or + result.(SequenceKind).getItem() instanceof CgiFieldStorageFieldKind + ) + } +} + +/** TaintKind for the field of a parsed HTTP form. */ +deprecated class CgiFieldStorageFieldKind extends TaintKind { + CgiFieldStorageFieldKind() { this = "CgiFieldStorageFieldKind" } + + override TaintKind getTaintOfAttribute(string name) { + name in ["filename", "value"] and result instanceof ExternalStringKind + or + name = "file" and result instanceof ExternalFileObject + } +} diff --git a/python/ql/lib/semmle/python/web/tornado/Request.qll b/python/ql/lib/semmle/python/web/tornado/Request.qll new file mode 100644 index 00000000000..77a02c230ae --- /dev/null +++ b/python/ql/lib/semmle/python/web/tornado/Request.qll @@ -0,0 +1,69 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.web.Http +import Tornado + +/** A tornado.request.HttpRequest object */ +deprecated class TornadoRequest extends TaintKind { + TornadoRequest() { this = "tornado.request.HttpRequest" } + + override TaintKind getTaintOfAttribute(string name) { + result instanceof ExternalStringDictKind and + ( + name = "headers" or + name = "cookies" + ) + or + result instanceof ExternalStringKind and + ( + name = "uri" or + name = "query" or + name = "body" + ) + or + result instanceof ExternalStringSequenceDictKind and + ( + name = "arguments" or + name = "query_arguments" or + name = "body_arguments" + ) + } +} + +deprecated class TornadoRequestSource extends HttpRequestTaintSource { + TornadoRequestSource() { isTornadoRequestHandlerInstance(this.(AttrNode).getObject("request")) } + + override string toString() { result = "Tornado request source" } + + override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoRequest } +} + +deprecated class TornadoExternalInputSource extends HttpRequestTaintSource { + TornadoExternalInputSource() { + exists(string name | + name in ["get_argument", "get_query_argument", "get_body_argument", "decode_argument"] + | + this = callToNamedTornadoRequestHandlerMethod(name) + ) + } + + override string toString() { result = "Tornado request method" } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } +} + +deprecated class TornadoExternalInputListSource extends HttpRequestTaintSource { + TornadoExternalInputListSource() { + exists(string name | + name = "get_arguments" or + name = "get_query_arguments" or + name = "get_body_arguments" + | + this = callToNamedTornadoRequestHandlerMethod(name) + ) + } + + override string toString() { result = "Tornado request method" } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } +} diff --git a/python/ql/lib/semmle/python/web/tornado/Tornado.qll b/python/ql/lib/semmle/python/web/tornado/Tornado.qll new file mode 100644 index 00000000000..798ecff43ff --- /dev/null +++ b/python/ql/lib/semmle/python/web/tornado/Tornado.qll @@ -0,0 +1,50 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.web.Http + +deprecated private ClassValue theTornadoRequestHandlerClass() { + result = Value::named("tornado.web.RequestHandler") +} + +deprecated ClassValue aTornadoRequestHandlerClass() { + result.getABaseType+() = theTornadoRequestHandlerClass() +} + +/** + * Holds if `node` is likely to refer to an instance of a tornado + * `RequestHandler` class. + */ +deprecated predicate isTornadoRequestHandlerInstance(ControlFlowNode node) { + node.pointsTo().getClass() = aTornadoRequestHandlerClass() + or + /* + * In some cases, the points-to analysis won't capture all instances we care + * about. For these, we use the following syntactic check. First, that + * `node` appears inside a method of a subclass of + * `tornado.web.RequestHandler`: + */ + + node.getScope().getEnclosingScope() = aTornadoRequestHandlerClass().getScope() and + /* Secondly, that `node` refers to the `self` argument: */ + node.isLoad() and + node.(NameNode).isSelf() +} + +deprecated CallNode callToNamedTornadoRequestHandlerMethod(string name) { + isTornadoRequestHandlerInstance(result.getFunction().(AttrNode).getObject(name)) +} + +deprecated class TornadoCookieSet extends CookieSet, CallNode { + TornadoCookieSet() { + exists(ControlFlowNode f | + f = this.getFunction().(AttrNode).getObject("set_cookie") and + isTornadoRequestHandlerInstance(f) + ) + } + + override string toString() { result = CallNode.super.toString() } + + override ControlFlowNode getKey() { result = this.getArg(0) } + + override ControlFlowNode getValue() { result = this.getArg(1) } +} diff --git a/python/ql/lib/semmle/python/web/turbogears/Request.qll b/python/ql/lib/semmle/python/web/turbogears/Request.qll new file mode 100644 index 00000000000..48e063d0f99 --- /dev/null +++ b/python/ql/lib/semmle/python/web/turbogears/Request.qll @@ -0,0 +1,26 @@ +import python +import semmle.python.security.strings.External +import semmle.python.web.Http +import TurboGears + +deprecated private class ValidatedMethodParameter extends Parameter { + ValidatedMethodParameter() { + exists(string name, TurboGearsControllerMethod method | + method.getArgByName(name) = this and + method.getValidationDict().getItem(_).(KeyValuePair).getKey().(StrConst).getText() = name + ) + } +} + +deprecated class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource { + UnvalidatedControllerMethodParameter() { + exists(Parameter p | + any(TurboGearsControllerMethod m | not m.getName() = "onerror").getAnArg() = p and + not p instanceof ValidatedMethodParameter and + not p.isSelf() and + p.(Name).getAFlowNode() = this + ) + } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/lib/semmle/python/web/turbogears/TurboGears.qll b/python/ql/lib/semmle/python/web/turbogears/TurboGears.qll new file mode 100644 index 00000000000..87006afe03a --- /dev/null +++ b/python/ql/lib/semmle/python/web/turbogears/TurboGears.qll @@ -0,0 +1,37 @@ +import python +import semmle.python.dataflow.TaintTracking + +deprecated private ClassValue theTurboGearsControllerClass() { + result = Value::named("tg.TGController") +} + +deprecated ClassValue aTurboGearsControllerClass() { + result.getABaseType+() = theTurboGearsControllerClass() +} + +deprecated class TurboGearsControllerMethod extends Function { + ControlFlowNode decorator; + + TurboGearsControllerMethod() { + aTurboGearsControllerClass().getScope() = this.getScope() and + decorator = this.getADecorator().getAFlowNode() and + /* Is decorated with @expose() or @expose(path) */ + ( + decorator.(CallNode).getFunction().(NameNode).getId() = "expose" + or + decorator.pointsTo().getClass() = Value::named("tg.expose") + ) + } + + private ControlFlowNode templateName() { result = decorator.(CallNode).getArg(0) } + + predicate isTemplated() { exists(this.templateName()) } + + Dict getValidationDict() { + exists(Call call | + call = this.getADecorator() and + call.getFunc().(Name).getId() = "validate" and + call.getArg(0).pointsTo(_, result) + ) + } +} diff --git a/python/ql/lib/semmle/python/web/twisted/Request.qll b/python/ql/lib/semmle/python/web/twisted/Request.qll new file mode 100644 index 00000000000..d1bcf879f0f --- /dev/null +++ b/python/ql/lib/semmle/python/web/twisted/Request.qll @@ -0,0 +1,30 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.web.Http +import Twisted + +/** A twisted.web.http.Request object */ +deprecated class TwistedRequest extends TaintKind { + TwistedRequest() { this = "twisted.request.http.Request" } + + override TaintKind getTaintOfAttribute(string name) { + result instanceof ExternalStringSequenceDictKind and + name = "args" + or + result instanceof ExternalStringKind and + name = "uri" + } + + override TaintKind getTaintOfMethodResult(string name) { + name in ["getHeader", "getCookie", "getUser", "getPassword"] and + result instanceof ExternalStringKind + } +} + +deprecated class TwistedRequestSource extends HttpRequestTaintSource { + TwistedRequestSource() { isTwistedRequestInstance(this) } + + override string toString() { result = "Twisted request source" } + + override predicate isSourceOf(TaintKind kind) { kind instanceof TwistedRequest } +} diff --git a/python/ql/lib/semmle/python/web/twisted/Twisted.qll b/python/ql/lib/semmle/python/web/twisted/Twisted.qll new file mode 100644 index 00000000000..54dd1d959e8 --- /dev/null +++ b/python/ql/lib/semmle/python/web/twisted/Twisted.qll @@ -0,0 +1,52 @@ +import python +import semmle.python.dataflow.TaintTracking + +deprecated private ClassValue theTwistedHttpRequestClass() { + result = Value::named("twisted.web.http.Request") +} + +deprecated private ClassValue theTwistedHttpResourceClass() { + result = Value::named("twisted.web.resource.Resource") +} + +deprecated ClassValue aTwistedRequestHandlerClass() { + result.getABaseType+() = theTwistedHttpResourceClass() +} + +deprecated FunctionValue getTwistedRequestHandlerMethod(string name) { + result = aTwistedRequestHandlerClass().declaredAttribute(name) +} + +bindingset[name] +deprecated predicate isKnownRequestHandlerMethodName(string name) { + name = "render" or + name.matches("render_%") +} + +/** + * Holds if `node` is likely to refer to an instance of the twisted + * `Request` class. + */ +deprecated predicate isTwistedRequestInstance(NameNode node) { + node.pointsTo().getClass() = theTwistedHttpRequestClass() + or + /* + * In points-to analysis cannot infer that a given object is an instance of + * the `twisted.web.http.Request` class, we also include any parameter + * called `request` that appears inside a subclass of a request handler + * class, and the appropriate arguments of known request handler methods. + */ + + exists(Function func | + func = node.getScope() and + func.getEnclosingScope() = aTwistedRequestHandlerClass().getScope() + | + /* Any parameter called `request` */ + node.getId() = "request" and + node.isParameter() + or + /* Any request parameter of a known request handler method */ + isKnownRequestHandlerMethodName(func.getName()) and + node.getNode() = func.getArg(1) + ) +} diff --git a/python/ql/lib/semmle/python/web/webob/Request.qll b/python/ql/lib/semmle/python/web/webob/Request.qll new file mode 100644 index 00000000000..3c085b1d02d --- /dev/null +++ b/python/ql/lib/semmle/python/web/webob/Request.qll @@ -0,0 +1,38 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.web.Http + +abstract deprecated class BaseWebobRequest extends TaintKind { + bindingset[this] + BaseWebobRequest() { any() } + + override TaintKind getTaintOfAttribute(string name) { + result instanceof ExternalStringDictKind and + ( + name = "GET" or + name = "POST" or + name = "headers" + ) + or + result instanceof ExternalStringKind and + name = "body" + } + + override TaintKind getTaintOfMethodResult(string name) { + result = this and + ( + name = "copy" or + name = "copy_get" or + name = "copy_body" + ) + or + result instanceof ExternalStringKind and + name = "as_bytes" + } +} + +deprecated class WebobRequest extends BaseWebobRequest { + WebobRequest() { this = "webob.Request" } + + override ClassValue getType() { result = Value::named("webob.request.Request") } +} diff --git a/python/ql/src/experimental/Security/CWE-074/TemplateInjection.qhelp b/python/ql/src/experimental/Security/CWE-074/TemplateInjection.qhelp new file mode 100644 index 00000000000..b044243fc8e --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-074/TemplateInjection.qhelp @@ -0,0 +1,24 @@ + + + +

    + Template Injection occurs when user input is embedded in a template in an unsafe manner. + When an attacker is able to use native template syntax to inject a malicious payload into a template, which is then executed server-side is results in Server Side Template Injection. +

    +
    + +

    + To fix this, ensure that an untrusted value is not used as a template. If the application requirements do not alow this, use a sandboxed environment where access to unsafe attributes and methods is prohibited. +

    +
    + +

    Consider the example given below, an untrusted HTTP parameter `template` is used to generate a Jinja2 template string. This can lead to remote code execution.

    + + +

    Here we have fixed the problem by using the Jinja sandbox environment for evaluating untrusted code.

    + +
    + +
  • Portswigger : [Server Side Template Injection](https://portswigger.net/web-security/server-side-template-injection)
  • +
    +
    diff --git a/python/ql/src/experimental/Security/CWE-074/TemplateInjection.ql b/python/ql/src/experimental/Security/CWE-074/TemplateInjection.ql new file mode 100644 index 00000000000..cbc3536ad7d --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-074/TemplateInjection.ql @@ -0,0 +1,35 @@ +/** + * @name Server Side Template Injection + * @description Using user-controlled data to create a template can cause security issues. + * @kind path-problem + * @problem.severity error + * @precision high + * @id py/template-injection + * @tags security + * experimental + * external/cwe/cwe-074 + */ + +import python +import semmle.python.security.Paths +/* Sources */ +import semmle.python.web.HttpRequest +/* Sinks */ +import experimental.semmle.python.templates.Ssti +/* Flow */ +import semmle.python.security.strings.Untrusted + +class TemplateInjectionConfiguration extends TaintTracking::Configuration { + TemplateInjectionConfiguration() { this = "Template injection configuration" } + + deprecated override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } + + deprecated override predicate isSink(TaintTracking::Sink sink) { sink instanceof SSTISink } +} + +from TemplateInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink +where config.hasFlowPath(src, sink) +select sink.getSink(), src, sink, "This Template depends on $@.", src.getSource(), + "a user-provided value" diff --git a/python/ql/src/experimental/Security/CWE-091/Xslt.qhelp b/python/ql/src/experimental/Security/CWE-091/Xslt.qhelp new file mode 100644 index 00000000000..307314f00df --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-091/Xslt.qhelp @@ -0,0 +1,18 @@ + + + +

    + Processing an unvalidated XSL stylesheet can allow an attacker to change the structure and contents of the resultant XML, include arbitrary files from the file system, or execute arbitrary code. +

    +
    + +

    + This vulnerability can be prevented by not allowing untrusted user input to be passed as an XSL stylesheet. + If the application logic necessitates processing untrusted XSL stylesheets, the input should be properly filtered and sanitized before use. +

    +
    + +

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

    + +
    +
    diff --git a/python/ql/src/experimental/Security/CWE-091/Xslt.ql b/python/ql/src/experimental/Security/CWE-091/Xslt.ql new file mode 100644 index 00000000000..77f405f5f5a --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-091/Xslt.ql @@ -0,0 +1,36 @@ +/** + * @name XSLT query built from user-controlled sources + * @description Building a XSLT query from user-controlled sources is vulnerable to insertion of + * malicious XSLT code by the user. + * @kind path-problem + * @problem.severity error + * @precision high + * @id py/xslt-injection + * @tags security + * experimental + * external/cwe/cwe-643 + */ + +import python +import semmle.python.security.Paths +/* Sources */ +import semmle.python.web.HttpRequest +/* Sinks */ +import experimental.semmle.python.security.injection.XSLT + +class XsltInjectionConfiguration extends TaintTracking::Configuration { + XsltInjectionConfiguration() { this = "XSLT injection configuration" } + + deprecated override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } + + deprecated override predicate isSink(TaintTracking::Sink sink) { + sink instanceof XSLTInjection::XSLTInjectionSink + } +} + +from XsltInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink +where config.hasFlowPath(src, sink) +select sink.getSink(), src, sink, "This XSLT query depends on $@.", src.getSource(), + "a user-provided value" diff --git a/python/ql/src/experimental/Security/CWE-091/xslt.py b/python/ql/src/experimental/Security/CWE-091/xslt.py new file mode 100644 index 00000000000..1655916c7e0 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-091/xslt.py @@ -0,0 +1,14 @@ +from lxml import etree +from io import StringIO +from flask import Flask, request + +app = Flask(__name__) + + +@app.route("/xslt") +def bad(): + xsltQuery = request.args.get('xml', '') + xslt_root = etree.XML(xsltQuery) + f = StringIO('') + tree = etree.parse(f) + result_tree = tree.xslt(xslt_root) # Not OK diff --git a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll index ff3f7189b18..4d0057f8dc1 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll @@ -8,6 +8,7 @@ import python import semmle.python.dataflow.TaintTracking +import semmle.python.web.HttpRequest /** Models XSLT Injection related classes and functions */ module XsltInjection { @@ -20,6 +21,21 @@ module XsltInjection { /** DEPRECATED: Alias for XsltInjectionSink */ deprecated class XSLTInjectionSink = XsltInjectionSink; + /** + * A kind of "taint", representing an untrusted XML string + */ + deprecated private class ExternalXmlStringKind extends ExternalStringKind { + ExternalXmlStringKind() { this = "etree.XML string" } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + etreeXml(fromnode, tonode) and result instanceof ExternalXmlKind + or + etreeFromStringList(fromnode, tonode) and result instanceof ExternalXmlKind + or + etreeFromString(fromnode, tonode) and result instanceof ExternalXmlKind + } + } + /** * A kind of "taint", representing a XML encoded string */ @@ -27,6 +43,32 @@ module XsltInjection { ExternalXmlKind() { this = "lxml etree xml" } } + private predicate etreeXml(ControlFlowNode fromnode, CallNode tonode) { + // etree.XML("") + exists(CallNode call | call.getFunction().(AttrNode).getObject("XML").pointsTo(etree()) | + call.getArg(0) = fromnode and + call = tonode + ) + } + + private predicate etreeFromString(ControlFlowNode fromnode, CallNode tonode) { + // etree.fromstring(text, parser=None) + exists(CallNode call | call.getFunction().(AttrNode).getObject("fromstring").pointsTo(etree()) | + call.getArg(0) = fromnode and + call = tonode + ) + } + + private predicate etreeFromStringList(ControlFlowNode fromnode, CallNode tonode) { + // etree.fromstringlist(strings, parser=None) + exists(CallNode call | + call.getFunction().(AttrNode).getObject("fromstringlist").pointsTo(etree()) + | + call.getArg(0) = fromnode and + call = tonode + ) + } + /** * A Sink representing an argument to the `etree.XSLT` call. * diff --git a/python/ql/src/experimental/semmle/python/templates/Airspeed.qll b/python/ql/src/experimental/semmle/python/templates/Airspeed.qll new file mode 100644 index 00000000000..dc266ac0f82 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/Airspeed.qll @@ -0,0 +1,27 @@ +/** Provides classes which model the `airspeed` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +/** returns the ClassValue representing `airspeed.Template` */ +deprecated ClassValue theAirspeedTemplateClass() { result = Value::named("airspeed.Template") } + +/** + * A sink representing the `airspeed.Template` class instantiation argument. + * + * import airspeed + * temp = airspeed.Template(`"sink"`) + */ +deprecated class AirspeedTemplateSink extends SSTISink { + override string toString() { result = "argument to airspeed.Template()" } + + AirspeedTemplateSink() { + exists(CallNode call | + call.getFunction().pointsTo(theAirspeedTemplateClass()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/src/experimental/semmle/python/templates/Bottle.qll b/python/ql/src/experimental/semmle/python/templates/Bottle.qll new file mode 100644 index 00000000000..1f5bd2bba85 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/Bottle.qll @@ -0,0 +1,48 @@ +/** Provides classes which model the `bottle` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +/** returns the ClassValue representing `bottle.SimpleTemplate` */ +deprecated ClassValue theBottleSimpleTemplateClass() { + result = Value::named("bottle.SimpleTemplate") +} + +/** + * A sink representing the `bottle.SimpleTemplate` class instantiation argument. + * + * from bottle import SimpleTemplate + * template = SimpleTemplate(`sink`) + */ +deprecated class BottleSimpleTemplateSink extends SSTISink { + override string toString() { result = "argument to bottle.SimpleTemplate()" } + + BottleSimpleTemplateSink() { + exists(CallNode call | + call.getFunction().pointsTo(theBottleSimpleTemplateClass()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} + +/** + * A sink representing the `bottle.template` function call argument. + * + * from bottle import template + * tmp = template(`sink`) + */ +deprecated class BottleTemplateSink extends SSTISink { + override string toString() { result = "argument to bottle.template()" } + + BottleTemplateSink() { + exists(CallNode call | + call.getFunction() = theBottleModule().attr("template").getAReference() and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/src/experimental/semmle/python/templates/Chameleon.qll b/python/ql/src/experimental/semmle/python/templates/Chameleon.qll new file mode 100644 index 00000000000..f094dda97b5 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/Chameleon.qll @@ -0,0 +1,29 @@ +/** Provides classes which model the `Chameleon` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +/** returns the ClassValue representing `chameleon.PageTemplate` */ +deprecated ClassValue theChameleonPageTemplateClass() { + result = Value::named("chameleon.PageTemplate") +} + +/** + * A sink representing the `chameleon.PageTemplate` class instantiation argument. + * + * from chameleon import PageTemplate + * template = PageTemplate(`sink`) + */ +deprecated class ChameleonTemplateSink extends SSTISink { + override string toString() { result = "argument to Chameleon.PageTemplate()" } + + ChameleonTemplateSink() { + exists(CallNode call | + call.getFunction().pointsTo(theChameleonPageTemplateClass()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/src/experimental/semmle/python/templates/Cheetah.qll b/python/ql/src/experimental/semmle/python/templates/Cheetah.qll new file mode 100644 index 00000000000..9812fdb7c88 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/Cheetah.qll @@ -0,0 +1,39 @@ +/** Provides classes which model the `Cheetah3` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +/** returns the ClassValue representing `Cheetah.Template.Template` */ +deprecated ClassValue theCheetahTemplateClass() { + result = Value::named("Cheetah.Template.Template") +} + +/** + * A sink representing the instantiation argument of any class which derives from + * the `Cheetah.Template.Template` class . + * + * from Cheetah.Template import Template + * class Template3(Template): + * title = 'Hello World Example!' + * contents = 'Hello World!' + * t3 = Template3("sink") + * + * This will also detect cases of the following type : + * + * from Cheetah.Template import Template + * t3 = Template("sink") + */ +deprecated class CheetahTemplateInstantiationSink extends SSTISink { + override string toString() { result = "argument to Cheetah.Template.Template()" } + + CheetahTemplateInstantiationSink() { + exists(CallNode call, ClassValue cv | + cv.getASuperType() = theCheetahTemplateClass() and + call.getFunction().pointsTo(cv) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/src/experimental/semmle/python/templates/Chevron.qll b/python/ql/src/experimental/semmle/python/templates/Chevron.qll new file mode 100644 index 00000000000..cc93016891c --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/Chevron.qll @@ -0,0 +1,36 @@ +/** Provides classes which model the `chevron` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +/** returns the Value representing `chevron.render` function */ +deprecated Value theChevronRenderFunc() { result = Value::named("chevron.render") } + +/** + * A sink representing the `chevron.render` function call argument. + * + * import chevron + * tmp = chevron.render(`sink`,{ 'key' : 'value' }) + */ +deprecated class ChevronRenderSink extends SSTISink { + override string toString() { result = "argument to chevron.render()" } + + ChevronRenderSink() { + exists(CallNode call | + call.getFunction() = theChevronRenderFunc().getAReference() and + call.getArg(0) = this + ) + // TODO: this should also detect : + // import chevron + // args = { + // 'template': 'sink', + // 'data': { + // 'mustache': 'World' + // } + // } + // chevron.render(**args) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll b/python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll new file mode 100644 index 00000000000..1089ab872ec --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll @@ -0,0 +1,35 @@ +/** Provides classes which model the `DjangoTemplate` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +deprecated ClassValue theDjangoTemplateClass() { result = Value::named("django.template.Template") } + +/** + * A sink representing `django.template.Template` class instantiation argument. + * + * from django.template import Template + * template = Template(`sink`) + */ +deprecated class DjangoTemplateTemplateSink extends SSTISink { + override string toString() { result = "argument to Django.template()" } + + DjangoTemplateTemplateSink() { + exists(CallNode call | + call.getFunction().pointsTo(theDjangoTemplateClass()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} +// TODO (intentionally commented out QLDoc, since qlformat will delete those lines otherwise) +// /** +// * Sinks representing the django.template.Template class instantiation. +// * +// * from django.template import engines +// * +// * django_engine = engines["django"] +// * template = django_engine.from_string(`sink`) +// */ diff --git a/python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll b/python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll new file mode 100644 index 00000000000..c0f3c90235d --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll @@ -0,0 +1,28 @@ +/** Provides classes which model templates in the`flask` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +deprecated Value theFlaskRenderTemplateClass() { + result = Value::named("flask.render_template_string") +} + +/** + * A sink representing `flask.render_template_string` function call argument. + * + * from flask import render_template_string + * render_template_string(`sink`) + */ +deprecated class FlaskTemplateSink extends SSTISink { + override string toString() { result = "argument to flask.render_template_string()" } + + FlaskTemplateSink() { + exists(CallNode call | + call.getFunction().pointsTo(theFlaskRenderTemplateClass()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/src/experimental/semmle/python/templates/Genshi.qll b/python/ql/src/experimental/semmle/python/templates/Genshi.qll new file mode 100644 index 00000000000..c808d7c60f8 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/Genshi.qll @@ -0,0 +1,53 @@ +/** Provides classes which model the `Genshi` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +/** returns the ClassValue representing `Genshi.template.TextTemplate` */ +deprecated ClassValue theGenshiTextTemplateClass() { + result = Value::named("genshi.template.TextTemplate") +} + +/** returns the ClassValue representing `Genshi.template.MarkupTemplate` */ +deprecated ClassValue theGenshiMarkupTemplateClass() { + result = Value::named("genshi.template.MarkupTemplate") +} + +/** + * A sink representing the `genshi.template.TextTemplate` class instantiation argument. + * + * from genshi.template import TextTemplate + * tmpl = TextTemplate('sink') + */ +deprecated class GenshiTextTemplateSink extends SSTISink { + override string toString() { result = "argument to genshi.template.TextTemplate()" } + + GenshiTextTemplateSink() { + exists(CallNode call | + call.getFunction().pointsTo(theGenshiTextTemplateClass()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} + +/** + * A sink representing the `genshi.template.MarkupTemplate` class instantiation argument. + * + * from genshi.template import MarkupTemplate + * tmpl = MarkupTemplate('sink') + */ +deprecated class GenshiMarkupTemplateSink extends SSTISink { + override string toString() { result = "argument to genshi.template.MarkupTemplate()" } + + GenshiMarkupTemplateSink() { + exists(CallNode call | + call.getFunction().pointsTo(theGenshiMarkupTemplateClass()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/src/experimental/semmle/python/templates/Jinja.qll b/python/ql/src/experimental/semmle/python/templates/Jinja.qll new file mode 100644 index 00000000000..44bc103cf04 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/Jinja.qll @@ -0,0 +1,49 @@ +/** Provides classes which model the `Jinja2` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +/** returns the ClassValue representing `jinja2.Template` */ +deprecated ClassValue theJinja2TemplateClass() { result = Value::named("jinja2.Template") } + +/** returns the ClassValue representing `jinja2.Template` */ +deprecated Value theJinja2FromStringValue() { result = Value::named("jinja2.from_string") } + +/** + * A sink representing the `jinja2.Template` class instantiation argument. + * + * from jinja2 import Template + * template = Template(`sink`) + */ +deprecated class Jinja2TemplateSink extends SSTISink { + override string toString() { result = "argument to jinja2.Template()" } + + Jinja2TemplateSink() { + exists(CallNode call | + call.getFunction().pointsTo(theJinja2TemplateClass()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} + +/** + * A sink representing the `jinja2.from_string` function call argument. + * + * from jinja2 import from_string + * template = from_string(`sink`) + */ +deprecated class Jinja2FromStringSink extends SSTISink { + override string toString() { result = "argument to jinja2.from_string()" } + + Jinja2FromStringSink() { + exists(CallNode call | + call.getFunction().pointsTo(theJinja2FromStringValue()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/src/experimental/semmle/python/templates/Mako.qll b/python/ql/src/experimental/semmle/python/templates/Mako.qll new file mode 100644 index 00000000000..b8634b3001a --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/Mako.qll @@ -0,0 +1,27 @@ +/** Provides classes which model the `Mako` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +/** returns the ClassValue representing `mako.template.Template` */ +deprecated ClassValue theMakoTemplateClass() { result = Value::named("mako.template.Template") } + +/** + * A sink representing the `mako.template.Template` class instantiation argument. + * + * from mako.template import Template + * mytemplate = Template("hello world!") + */ +deprecated class MakoTemplateSink extends SSTISink { + override string toString() { result = "argument to mako.template.Template()" } + + MakoTemplateSink() { + exists(CallNode call | + call.getFunction().pointsTo(theMakoTemplateClass()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/src/experimental/semmle/python/templates/SSTISink.qll b/python/ql/src/experimental/semmle/python/templates/SSTISink.qll new file mode 100644 index 00000000000..1a68fe17b68 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/SSTISink.qll @@ -0,0 +1,7 @@ +import semmle.python.dataflow.TaintTracking + +/** + * A generic taint sink that is vulnerable to template inclusions. + * The `temp` in `jinja2.Template(temp)` and similar. + */ +abstract deprecated class SSTISink extends TaintSink { } diff --git a/python/ql/src/experimental/semmle/python/templates/Ssti.qll b/python/ql/src/experimental/semmle/python/templates/Ssti.qll new file mode 100644 index 00000000000..eb4f8d0ec2f --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/Ssti.qll @@ -0,0 +1,13 @@ +/** Imports all files which model potential SSTI sinks */ + +import experimental.semmle.python.templates.Airspeed +import experimental.semmle.python.templates.Bottle +import experimental.semmle.python.templates.Chameleon +import experimental.semmle.python.templates.Cheetah +import experimental.semmle.python.templates.Chevron +import experimental.semmle.python.templates.DjangoTemplate +import experimental.semmle.python.templates.FlaskTemplate +import experimental.semmle.python.templates.Genshi +import experimental.semmle.python.templates.Jinja +import experimental.semmle.python.templates.Mako +import experimental.semmle.python.templates.TRender diff --git a/python/ql/src/experimental/semmle/python/templates/TRender.qll b/python/ql/src/experimental/semmle/python/templates/TRender.qll new file mode 100644 index 00000000000..8d5431ad9e0 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/templates/TRender.qll @@ -0,0 +1,27 @@ +/** Provides classes which model the `TRender` package. */ + +import python +import semmle.python.web.HttpRequest +import experimental.semmle.python.templates.SSTISink + +/** returns the ClassValue representing `trender.TRender` */ +deprecated ClassValue theTRenderTemplateClass() { result = Value::named("trender.TRender") } + +/** + * A sink representing the `trender.TRender` class instantiation argument. + * + * from trender import TRender + * template = TRender(`sink`) + */ +deprecated class TRenderTemplateSink extends SSTISink { + override string toString() { result = "argument to trender.TRender()" } + + TRenderTemplateSink() { + exists(CallNode call | + call.getFunction().pointsTo(theTRenderTemplateClass()) and + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } +} diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.expected new file mode 100644 index 00000000000..058a53bdf91 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.expected @@ -0,0 +1,60 @@ +edges +| AirspeedSsti.py:10:16:10:27 | dict of externally controlled string | AirspeedSsti.py:10:16:10:43 | externally controlled string | +| AirspeedSsti.py:10:16:10:27 | dict of externally controlled string | AirspeedSsti.py:10:16:10:43 | externally controlled string | +| AirspeedSsti.py:10:16:10:43 | externally controlled string | AirspeedSsti.py:11:30:11:37 | externally controlled string | +| AirspeedSsti.py:10:16:10:43 | externally controlled string | AirspeedSsti.py:11:30:11:37 | externally controlled string | +| ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:10:16:10:43 | externally controlled string | +| ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:10:16:10:43 | externally controlled string | +| ChevronSsti.py:10:16:10:43 | externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string | +| ChevronSsti.py:10:16:10:43 | externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string | +| DjangoTemplates.py:6:8:6:14 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest | +| DjangoTemplates.py:6:8:6:14 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest | +| DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict | +| DjangoTemplates.py:8:16:8:22 | django.request.HttpRequest | DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict | +| DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict | DjangoTemplates.py:8:16:8:38 | externally controlled string | +| DjangoTemplates.py:8:16:8:26 | django.http.request.QueryDict | DjangoTemplates.py:8:16:8:38 | externally controlled string | +| DjangoTemplates.py:8:16:8:38 | externally controlled string | DjangoTemplates.py:9:18:9:25 | externally controlled string | +| DjangoTemplates.py:8:16:8:38 | externally controlled string | DjangoTemplates.py:9:18:9:25 | externally controlled string | +| FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string | +| FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string | +| JinjaSsti.py:7:7:7:13 | django.request.HttpRequest | JinjaSsti.py:9:16:9:22 | django.request.HttpRequest | +| JinjaSsti.py:7:7:7:13 | django.request.HttpRequest | JinjaSsti.py:9:16:9:22 | django.request.HttpRequest | +| JinjaSsti.py:9:16:9:22 | django.request.HttpRequest | JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict | +| JinjaSsti.py:9:16:9:22 | django.request.HttpRequest | JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict | +| JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict | JinjaSsti.py:9:16:9:38 | externally controlled string | +| JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict | JinjaSsti.py:9:16:9:38 | externally controlled string | +| JinjaSsti.py:9:16:9:38 | externally controlled string | JinjaSsti.py:10:25:10:32 | externally controlled string | +| JinjaSsti.py:9:16:9:38 | externally controlled string | JinjaSsti.py:10:25:10:32 | externally controlled string | +| JinjaSsti.py:16:7:16:13 | django.request.HttpRequest | JinjaSsti.py:19:16:19:22 | django.request.HttpRequest | +| JinjaSsti.py:16:7:16:13 | django.request.HttpRequest | JinjaSsti.py:19:16:19:22 | django.request.HttpRequest | +| JinjaSsti.py:19:16:19:22 | django.request.HttpRequest | JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict | +| JinjaSsti.py:19:16:19:22 | django.request.HttpRequest | JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict | +| JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict | JinjaSsti.py:19:16:19:38 | externally controlled string | +| JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict | JinjaSsti.py:19:16:19:38 | externally controlled string | +| JinjaSsti.py:19:16:19:38 | externally controlled string | JinjaSsti.py:20:28:20:35 | externally controlled string | +| JinjaSsti.py:19:16:19:38 | externally controlled string | JinjaSsti.py:20:28:20:35 | externally controlled string | +| MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:8:16:8:22 | django.request.HttpRequest | +| MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:8:16:8:22 | django.request.HttpRequest | +| MakoSsti.py:8:16:8:22 | django.request.HttpRequest | MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | +| MakoSsti.py:8:16:8:22 | django.request.HttpRequest | MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | +| MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | MakoSsti.py:8:16:8:38 | externally controlled string | +| MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | MakoSsti.py:8:16:8:38 | externally controlled string | +| MakoSsti.py:8:16:8:38 | externally controlled string | MakoSsti.py:9:27:9:34 | externally controlled string | +| MakoSsti.py:8:16:8:38 | externally controlled string | MakoSsti.py:9:27:9:34 | externally controlled string | +| TRender.py:5:13:5:19 | django.request.HttpRequest | TRender.py:6:16:6:22 | django.request.HttpRequest | +| TRender.py:5:13:5:19 | django.request.HttpRequest | TRender.py:6:16:6:22 | django.request.HttpRequest | +| TRender.py:6:16:6:22 | django.request.HttpRequest | TRender.py:6:16:6:26 | django.http.request.QueryDict | +| TRender.py:6:16:6:22 | django.request.HttpRequest | TRender.py:6:16:6:26 | django.http.request.QueryDict | +| TRender.py:6:16:6:26 | django.http.request.QueryDict | TRender.py:6:16:6:38 | externally controlled string | +| TRender.py:6:16:6:26 | django.http.request.QueryDict | TRender.py:6:16:6:38 | externally controlled string | +| TRender.py:6:16:6:38 | externally controlled string | TRender.py:7:24:7:31 | externally controlled string | +| TRender.py:6:16:6:38 | externally controlled string | TRender.py:7:24:7:31 | externally controlled string | +#select +| AirspeedSsti.py:11:30:11:37 | template | AirspeedSsti.py:10:16:10:27 | dict of externally controlled string | AirspeedSsti.py:11:30:11:37 | externally controlled string | This Template depends on $@. | AirspeedSsti.py:10:16:10:27 | Attribute | a user-provided value | +| ChevronSsti.py:11:27:11:34 | template | ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string | This Template depends on $@. | ChevronSsti.py:10:16:10:27 | Attribute | a user-provided value | +| DjangoTemplates.py:9:18:9:25 | template | DjangoTemplates.py:6:8:6:14 | django.request.HttpRequest | DjangoTemplates.py:9:18:9:25 | externally controlled string | This Template depends on $@. | DjangoTemplates.py:6:8:6:14 | request | a user-provided value | +| FlaskTemplate.py:17:41:17:68 | Attribute() | FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string | This Template depends on $@. | FlaskTemplate.py:17:41:17:52 | Attribute | a user-provided value | +| JinjaSsti.py:10:25:10:32 | template | JinjaSsti.py:7:7:7:13 | django.request.HttpRequest | JinjaSsti.py:10:25:10:32 | externally controlled string | This Template depends on $@. | JinjaSsti.py:7:7:7:13 | request | a user-provided value | +| JinjaSsti.py:20:28:20:35 | template | JinjaSsti.py:16:7:16:13 | django.request.HttpRequest | JinjaSsti.py:20:28:20:35 | externally controlled string | This Template depends on $@. | JinjaSsti.py:16:7:16:13 | request | a user-provided value | +| MakoSsti.py:9:27:9:34 | template | MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:9:27:9:34 | externally controlled string | This Template depends on $@. | MakoSsti.py:6:10:6:16 | request | a user-provided value | +| TRender.py:7:24:7:31 | template | TRender.py:5:13:5:19 | django.request.HttpRequest | TRender.py:7:24:7:31 | externally controlled string | This Template depends on $@. | TRender.py:5:13:5:19 | request | a user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.qlref b/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.qlref new file mode 100644 index 00000000000..90efec9f636 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-074/TemplateInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-074/TemplateInjection.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.expected b/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.expected new file mode 100644 index 00000000000..89f19160f69 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.expected @@ -0,0 +1,47 @@ +edges +| xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:10:17:10:43 | etree.XML string | +| xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:10:17:10:43 | etree.XML string | +| xslt.py:10:17:10:43 | etree.XML string | xslt.py:11:27:11:35 | etree.XML string | +| xslt.py:10:17:10:43 | etree.XML string | xslt.py:11:27:11:35 | etree.XML string | +| xslt.py:11:17:11:36 | lxml etree xml | xslt.py:14:29:14:37 | lxml etree xml | +| xslt.py:11:17:11:36 | lxml etree xml | xslt.py:14:29:14:37 | lxml etree xml | +| xslt.py:11:27:11:35 | etree.XML string | xslt.py:11:17:11:36 | lxml etree xml | +| xslt.py:11:27:11:35 | etree.XML string | xslt.py:11:17:11:36 | lxml etree xml | +| xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:10:17:10:43 | etree.XML string | +| xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:10:17:10:43 | etree.XML string | +| xsltInjection.py:10:17:10:43 | etree.XML string | xsltInjection.py:11:27:11:35 | etree.XML string | +| xsltInjection.py:10:17:10:43 | etree.XML string | xsltInjection.py:11:27:11:35 | etree.XML string | +| xsltInjection.py:11:17:11:36 | lxml etree xml | xsltInjection.py:12:28:12:36 | lxml etree xml | +| xsltInjection.py:11:17:11:36 | lxml etree xml | xsltInjection.py:12:28:12:36 | lxml etree xml | +| xsltInjection.py:11:27:11:35 | etree.XML string | xsltInjection.py:11:17:11:36 | lxml etree xml | +| xsltInjection.py:11:27:11:35 | etree.XML string | xsltInjection.py:11:17:11:36 | lxml etree xml | +| xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:17:17:17:43 | etree.XML string | +| xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:17:17:17:43 | etree.XML string | +| xsltInjection.py:17:17:17:43 | etree.XML string | xsltInjection.py:18:27:18:35 | etree.XML string | +| xsltInjection.py:17:17:17:43 | etree.XML string | xsltInjection.py:18:27:18:35 | etree.XML string | +| xsltInjection.py:18:17:18:36 | lxml etree xml | xsltInjection.py:21:29:21:37 | lxml etree xml | +| xsltInjection.py:18:17:18:36 | lxml etree xml | xsltInjection.py:21:29:21:37 | lxml etree xml | +| xsltInjection.py:18:27:18:35 | etree.XML string | xsltInjection.py:18:17:18:36 | lxml etree xml | +| xsltInjection.py:18:27:18:35 | etree.XML string | xsltInjection.py:18:17:18:36 | lxml etree xml | +| xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:26:17:26:43 | etree.XML string | +| xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:26:17:26:43 | etree.XML string | +| xsltInjection.py:26:17:26:43 | etree.XML string | xsltInjection.py:27:27:27:35 | etree.XML string | +| xsltInjection.py:26:17:26:43 | etree.XML string | xsltInjection.py:27:27:27:35 | etree.XML string | +| xsltInjection.py:27:17:27:36 | lxml etree xml | xsltInjection.py:31:24:31:32 | lxml etree xml | +| xsltInjection.py:27:17:27:36 | lxml etree xml | xsltInjection.py:31:24:31:32 | lxml etree xml | +| xsltInjection.py:27:27:27:35 | etree.XML string | xsltInjection.py:27:17:27:36 | lxml etree xml | +| xsltInjection.py:27:27:27:35 | etree.XML string | xsltInjection.py:27:17:27:36 | lxml etree xml | +| xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:35:17:35:43 | etree.XML string | +| xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:35:17:35:43 | etree.XML string | +| xsltInjection.py:35:17:35:43 | etree.XML string | xsltInjection.py:36:34:36:42 | etree.XML string | +| xsltInjection.py:35:17:35:43 | etree.XML string | xsltInjection.py:36:34:36:42 | etree.XML string | +| xsltInjection.py:36:17:36:43 | lxml etree xml | xsltInjection.py:40:24:40:32 | lxml etree xml | +| xsltInjection.py:36:17:36:43 | lxml etree xml | xsltInjection.py:40:24:40:32 | lxml etree xml | +| xsltInjection.py:36:34:36:42 | etree.XML string | xsltInjection.py:36:17:36:43 | lxml etree xml | +| xsltInjection.py:36:34:36:42 | etree.XML string | xsltInjection.py:36:17:36:43 | lxml etree xml | +#select +| xslt.py:14:29:14:37 | xslt_root | xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:14:29:14:37 | lxml etree xml | This XSLT query depends on $@. | xslt.py:10:17:10:28 | Attribute | a user-provided value | +| xsltInjection.py:12:28:12:36 | xslt_root | xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:12:28:12:36 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:10:17:10:28 | Attribute | a user-provided value | +| xsltInjection.py:21:29:21:37 | xslt_root | xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:21:29:21:37 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:17:17:17:28 | Attribute | a user-provided value | +| xsltInjection.py:31:24:31:32 | xslt_root | xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:31:24:31:32 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:26:17:26:28 | Attribute | a user-provided value | +| xsltInjection.py:40:24:40:32 | xslt_root | xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:40:24:40:32 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:35:17:35:28 | Attribute | a user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.qlref b/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.qlref new file mode 100644 index 00000000000..988d13e98a6 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-091/Xslt.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-091/Xslt.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091/XsltSinks.expected b/python/ql/test/experimental/query-tests/Security/CWE-091/XsltSinks.expected index dec055bc8e0..7150b3046e2 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-091/XsltSinks.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-091/XsltSinks.expected @@ -1,3 +1,4 @@ +| xslt.py:14:29:14:37 | lxml.etree.parse.xslt | lxml etree xml | | xsltInjection.py:12:28:12:36 | lxml.etree.XSLT | lxml etree xml | | xsltInjection.py:21:29:21:37 | lxml.etree.parse.xslt | lxml etree xml | | xsltInjection.py:31:24:31:32 | lxml.etree.parse.xslt | lxml etree xml | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091/xslt.py b/python/ql/test/experimental/query-tests/Security/CWE-091/xslt.py new file mode 100644 index 00000000000..1655916c7e0 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-091/xslt.py @@ -0,0 +1,14 @@ +from lxml import etree +from io import StringIO +from flask import Flask, request + +app = Flask(__name__) + + +@app.route("/xslt") +def bad(): + xsltQuery = request.args.get('xml', '') + xslt_root = etree.XML(xsltQuery) + f = StringIO('') + tree = etree.parse(f) + result_tree = tree.xslt(xslt_root) # Not OK From 8663a8ba1c6db3e633a2e305d4563494bd15f906 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Wed, 14 Jun 2023 08:24:39 +0200 Subject: [PATCH 093/364] add change-note --- python/ql/lib/change-notes/2023-06-14-delete-deps.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/lib/change-notes/2023-06-14-delete-deps.md diff --git a/python/ql/lib/change-notes/2023-06-14-delete-deps.md b/python/ql/lib/change-notes/2023-06-14-delete-deps.md new file mode 100644 index 00000000000..16946163f5e --- /dev/null +++ b/python/ql/lib/change-notes/2023-06-14-delete-deps.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Deleted many models that used the old dataflow library, the new models can be found in the `python/ql/lib/semmle/python/frameworks` folder. \ No newline at end of file From 5e3d9d8136eb2e846aa2ee00ca3ea01fd194adda Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 23 May 2023 15:21:50 +0200 Subject: [PATCH 094/364] Java: Model the Stapler framework --- .../change-notes/2023-05-22-stapler-models.md | 4 + .../ext/org.kohsuke.stapler.bind.model.yml | 6 + .../ext/org.kohsuke.stapler.json.model.yml | 7 + java/ql/lib/ext/org.kohsuke.stapler.model.yml | 42 ++++++ .../semmle/code/java/dataflow/FlowSources.qll | 1 + .../semmle/code/java/dataflow/FlowSteps.qll | 1 + .../code/java/frameworks/hudson/Hudson.qll | 9 ++ .../code/java/frameworks/stapler/Stapler.qll | 124 ++++++++++++++++++ .../dataflow/taintsources/Stapler.java | 14 ++ .../dataflow/taintsources/options | 2 +- .../stapler/DataBoundPostConstructTest.java | 42 ++++++ .../frameworks/stapler/HttpResponseTest.java | 26 ++++ .../library-tests/frameworks/stapler/options | 2 +- .../javax/annotation/PostConstruct.java | 13 ++ .../jenkins/hudson/model/Descriptor.java | 5 + .../kohsuke/stapler/DataBoundConstructor.java | 13 ++ .../kohsuke/stapler/DataBoundResolvable.java | 4 + .../org/kohsuke/stapler/DataBoundSetter.java | 14 ++ .../kohsuke/stapler/InjectedParameter.java | 13 ++ 19 files changed, 340 insertions(+), 2 deletions(-) create mode 100644 java/ql/lib/change-notes/2023-05-22-stapler-models.md create mode 100644 java/ql/lib/ext/org.kohsuke.stapler.bind.model.yml create mode 100644 java/ql/lib/ext/org.kohsuke.stapler.json.model.yml create mode 100644 java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll create mode 100644 java/ql/test/library-tests/dataflow/taintsources/Stapler.java create mode 100644 java/ql/test/library-tests/frameworks/stapler/DataBoundPostConstructTest.java create mode 100644 java/ql/test/library-tests/frameworks/stapler/HttpResponseTest.java create mode 100644 java/ql/test/stubs/javax-annotation-api-1.3.2/javax/annotation/PostConstruct.java create mode 100644 java/ql/test/stubs/jenkins/hudson/model/Descriptor.java create mode 100644 java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundConstructor.java create mode 100644 java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundResolvable.java create mode 100644 java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundSetter.java create mode 100644 java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/InjectedParameter.java diff --git a/java/ql/lib/change-notes/2023-05-22-stapler-models.md b/java/ql/lib/change-notes/2023-05-22-stapler-models.md new file mode 100644 index 00000000000..37c7250b953 --- /dev/null +++ b/java/ql/lib/change-notes/2023-05-22-stapler-models.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added more models for the Stapler framework. diff --git a/java/ql/lib/ext/org.kohsuke.stapler.bind.model.yml b/java/ql/lib/ext/org.kohsuke.stapler.bind.model.yml new file mode 100644 index 00000000000..9152eb7b55b --- /dev/null +++ b/java/ql/lib/ext/org.kohsuke.stapler.bind.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sourceModel + data: + - ["org.kohsuke.stapler.bind", "JavaScriptMethod", True, "", "", "Annotated", "Parameter", "remote", "manual"] diff --git a/java/ql/lib/ext/org.kohsuke.stapler.json.model.yml b/java/ql/lib/ext/org.kohsuke.stapler.json.model.yml new file mode 100644 index 00000000000..a06683144e0 --- /dev/null +++ b/java/ql/lib/ext/org.kohsuke.stapler.json.model.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/java-all + extensible: sourceModel + data: + - ["org.kohsuke.stapler.json", "SubmittedForm", True, "", "", "Annotated", "Parameter", "remote", "manual"] + - ["org.kohsuke.stapler.json", "JsonBody", True, "", "", "Annotated", "Parameter", "remote", "manual"] diff --git a/java/ql/lib/ext/org.kohsuke.stapler.model.yml b/java/ql/lib/ext/org.kohsuke.stapler.model.yml index 7a242051485..63bbdbfd52a 100644 --- a/java/ql/lib/ext/org.kohsuke.stapler.model.yml +++ b/java/ql/lib/ext/org.kohsuke.stapler.model.yml @@ -4,4 +4,46 @@ extensions: extensible: sinkModel data: - ["org.kohsuke.stapler", "HttpResponses", True, "redirectTo", "(String)", "", "Argument[0]", "url-redirection", "ai-manual"] + - ["org.kohsuke.stapler", "HttpResponses", True, "redirectTo", "(int,String)", "", "Argument[1]", "url-redirection", "manual"] - ["org.kohsuke.stapler", "HttpResponses", True, "staticResource", "(URL)", "", "Argument[0]", "request-forgery", "ai-manual"] + - ["org.kohsuke.stapler", "HttpResponses", True, "staticResource", "(URL,long)", "", "Argument[0]", "request-forgery", "manual"] + - ["org.kohsuke.stapler", "HttpResponses", True, "html", "(String)", "", "Argument[0]", "html-injection", "manual"] + - ["org.kohsuke.stapler", "HttpResponses", True, "literalHtml", "(String)", "", "Argument[0]", "html-injection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "forward", "(Object,String,StaplerRequest)", "", "Argument[1]", "request-forgery", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "sendRedirect2", "(String)", "", "Argument[0]", "url-redirection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "sendRedirect", "(int,String)", "", "Argument[1]", "url-redirection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "sendRedirect", "(String)", "", "Argument[0]", "url-redirection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "serveFile", "(StaplerRequest,URL)", "", "Argument[1]", "path-injection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "serveFile", "(StaplerRequest,URL,long)", "", "Argument[1]", "path-injection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "serveLocalizedFile", "(StaplerRequest,URL)", "", "Argument[1]", "path-injection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "serveLocalizedFile", "(StaplerRequest,URL,long)", "", "Argument[1]", "path-injection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "serveFile", "(StaplerRequest,InputStream,long,long,long,String)", "", "Argument[1]", "path-injection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "serveFile", "(StaplerRequest,InputStream,long,long,int,String)", "", "Argument[1]", "path-injection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "serveFile", "(StaplerRequest,InputStream,long,long,String)", "", "Argument[1]", "path-injection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "serveFile", "(StaplerRequest,InputStream,long,int,String)", "", "Argument[1]", "path-injection", "manual"] + - ["org.kohsuke.stapler", "StaplerResponse", True, "reverseProxyTo", "(URL,StaplerRequest)", "", "Argument[0]", "request-forgery", "manual"] + - addsTo: + pack: codeql/java-all + extensible: sourceModel + data: + - ["org.kohsuke.stapler", "StaplerRequest", True, "getRequestURIWithQueryString", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "getRequestURLWithQueryString", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "getReferer", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "getOriginalRequestURI", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "getSubmittedForm", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "getFileItem", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "bindParametersToList", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "bindParameters", "", "", "Argument[0]", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "bindParameters", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "bindJSON", "", "", "Argument[0]", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "bindJSON", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "bindJSONToList", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "getParameter", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "getParameterMap", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "getParameterNames", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "getParameterValues", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "StaplerRequest", True, "getRestOfPath", "", "", "ReturnValue", "remote", "manual"] + - ["org.kohsuke.stapler", "QueryParameter", True, "", "", "Annotated", "Parameter", "remote", "manual"] + - ["org.kohsuke.stapler", "Header", True, "", "", "Annotated", "Parameter", "remote", "manual"] + - ["org.kohsuke.stapler", "DataBoundConstructor", True, "", "", "Annotated", "Parameter", "remote", "manual"] + - ["org.kohsuke.stapler", "DataBoundSetter", True, "", "", "Annotated", "Parameter", "remote", "manual"] diff --git a/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll b/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll index 1a009c1f2e6..f049a0cb37b 100644 --- a/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll @@ -41,6 +41,7 @@ abstract class RemoteFlowSource extends DataFlow::Node { */ private module FlowSources { private import semmle.code.java.frameworks.hudson.Hudson + private import semmle.code.java.frameworks.stapler.Stapler } private class ExternalRemoteFlowSource extends RemoteFlowSource { diff --git a/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll b/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll index 9a187c027ff..1619965f0f0 100644 --- a/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll +++ b/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll @@ -23,6 +23,7 @@ private module Frameworks { private import semmle.code.java.frameworks.Properties private import semmle.code.java.frameworks.Protobuf private import semmle.code.java.frameworks.ratpack.RatpackExec + private import semmle.code.java.frameworks.stapler.Stapler private import semmle.code.java.JDK } diff --git a/java/ql/lib/semmle/code/java/frameworks/hudson/Hudson.qll b/java/ql/lib/semmle/code/java/frameworks/hudson/Hudson.qll index aab962e65aa..c283c23a046 100644 --- a/java/ql/lib/semmle/code/java/frameworks/hudson/Hudson.qll +++ b/java/ql/lib/semmle/code/java/frameworks/hudson/Hudson.qll @@ -2,8 +2,17 @@ import java private import semmle.code.java.dataflow.FlowSources +private import semmle.code.java.frameworks.stapler.Stapler private import semmle.code.java.security.XSS +/** A method declared in a subtype of `hudson.model.Descriptor` that returns an `HttpResponse`. */ +class HudsonWebMethod extends Method { + HudsonWebMethod() { + this.getReturnType().(RefType).getASourceSupertype*() instanceof HttpResponse and + this.getDeclaringType().getASourceSupertype*().hasQualifiedName("hudson.model", "Descriptor") + } +} + private class FilePathRead extends LocalUserInput { FilePathRead() { this.asExpr() diff --git a/java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll b/java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll new file mode 100644 index 00000000000..dbccfc99c04 --- /dev/null +++ b/java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll @@ -0,0 +1,124 @@ +/** Provides classes and predicates related to the Stapler framework. */ + +import java +private import semmle.code.java.dataflow.DataFlow +private import semmle.code.java.dataflow.FlowSources +private import semmle.code.java.dataflow.FlowSteps +private import semmle.code.java.dataflow.TypeFlow +private import semmle.code.java.frameworks.hudson.Hudson +private import semmle.code.java.frameworks.JavaxAnnotations + +/** + * A callable annotated with a Stapler `DataBound` annotation, + * or that has the `@stapler-constructor` Javadoc annotation. + */ +class DataBoundAnnotated extends Callable { + DataBoundAnnotated() { + exists(Annotation an | + an.getType() + .hasQualifiedName("org.kohsuke.stapler", ["DataBoundConstructor", "DataBoundSetter"]) + | + this = an.getAnnotatedElement() + ) + or + exists(Javadoc doc | doc.getAChild().getText().matches("%@stapler-constructor%") | + doc.getCommentedElement() = this + ) + } +} + +/** The interface `org.kohsuke.stapler.HttpResponse`. */ +class HttpResponse extends Interface { + HttpResponse() { this.hasQualifiedName("org.kohsuke.stapler", "HttpResponse") } +} + +/** + * A remote flow source for parameters annotated with an annotation + * that is itself annotated with `InjectedParameter`. + * + * Such parameters are populated with user-provided data by Stapler. + */ +private class InjectedParameterSource extends RemoteFlowSource { + InjectedParameterSource() { + this.asParameter().getAnAnnotation().getType() instanceof InjectedParameterAnnotatedType + } + + override string getSourceType() { result = "Stapler injected parameter" } +} + +/** + * A dataflow step from the `HttpResponse` return value of a `HudsonWebMethod` + * to the instance parameter of the `generateResponse` method of the appropriate subtype of `HttpResponse`. + * + * This models the rendering process of an `HttpResponse` by Stapler. + */ +private class HttpResponseGetDescriptionStep extends AdditionalValueStep { + override predicate step(DataFlow::Node n1, DataFlow::Node n2) { + exists(ReturnStmt s, GenerateResponseMethod m | + s.getEnclosingCallable() instanceof HudsonWebMethod and + boundOrStaticType(s.getResult(), m.getDeclaringType().getADescendant()) + | + n1.asExpr() = s.getResult() and + n2.(DataFlow::InstanceParameterNode).getCallable() = m + ) + } +} + +/** + * A dataflow step from the post-update node of an instance access in a `DataBoundAnnotated` method + * to the instance parameter of a `PostConstruct` method of the same type. + * + * This models the construction process of a `DataBound` object in Stapler. + */ +private class PostConstructDataBoundAdditionalStep extends AdditionalValueStep { + override predicate step(DataFlow::Node n1, DataFlow::Node n2) { + exists(PostConstructDataBoundMethod postConstruct, DataBoundAnnotated input | + postConstruct.getDeclaringType() = input.getDeclaringType() + | + n1.(DataFlow::PostUpdateNode) + .getPreUpdateNode() + .(DataFlow::InstanceAccessNode) + .getEnclosingCallable() = input and + n2.(DataFlow::InstanceParameterNode).getCallable() = postConstruct + ) + } +} + +/** An annotation type annotated with the `InjectedParameter` annotation. */ +private class InjectedParameterAnnotatedType extends AnnotationType { + InjectedParameterAnnotatedType() { + this.getAnAnnotation().getType().hasQualifiedName("org.kohsuke.stapler", "InjectedParameter") + } +} + +/** The `generateResponse` method of `org.kohsuke.stapler.HttpResponse` or its subtypes. */ +private class GenerateResponseMethod extends Method { + GenerateResponseMethod() { + this.getDeclaringType().getASourceSupertype*() instanceof HttpResponse and + this.hasName("generateResponse") + } +} + +/** Gets the static type of `e`, or an upper bound of the runtime type of `e`. */ +private predicate boundOrStaticType(Expr e, RefType t) { + exprTypeFlow(e, t, false) + or + t = e.getType() +} + +/** + * A method called after the construction of a `DataBound` object. + * + * That is, either the `bindResolve` method of a subtype of `org.kohsuke.stapler.DataBoundResolvable`, + * or a method annotated with `javax.annotation.PostConstruct`. + */ +private class PostConstructDataBoundMethod extends Method { + PostConstructDataBoundMethod() { + this.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("org.kohsuke.stapler", "DataBoundResolvable") and + this.hasName("bindResolve") + or + this.getAnAnnotation() instanceof PostConstructAnnotation + } +} diff --git a/java/ql/test/library-tests/dataflow/taintsources/Stapler.java b/java/ql/test/library-tests/dataflow/taintsources/Stapler.java new file mode 100644 index 00000000000..96be00270ba --- /dev/null +++ b/java/ql/test/library-tests/dataflow/taintsources/Stapler.java @@ -0,0 +1,14 @@ +import org.kohsuke.stapler.InjectedParameter; + +public class Stapler { + + @InjectedParameter + private @interface MyInjectedParameter { + } + + private static void sink(Object o) {} + + public static void test(@MyInjectedParameter String src) { + sink(src); // $ hasRemoteValueFlow + } +} diff --git a/java/ql/test/library-tests/dataflow/taintsources/options b/java/ql/test/library-tests/dataflow/taintsources/options index bd30b3e8c95..c8249b05e38 100644 --- a/java/ql/test/library-tests/dataflow/taintsources/options +++ b/java/ql/test/library-tests/dataflow/taintsources/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/akka-2.6.x:${testdir}/../../../stubs/jwtk-jjwt-0.11.2:${testdir}/../../../stubs/jenkins \ No newline at end of file +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/akka-2.6.x:${testdir}/../../../stubs/jwtk-jjwt-0.11.2:${testdir}/../../../stubs/jenkins:${testdir}/../../../stubs/stapler-1.263 \ No newline at end of file diff --git a/java/ql/test/library-tests/frameworks/stapler/DataBoundPostConstructTest.java b/java/ql/test/library-tests/frameworks/stapler/DataBoundPostConstructTest.java new file mode 100644 index 00000000000..efab6d956d2 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/stapler/DataBoundPostConstructTest.java @@ -0,0 +1,42 @@ +import javax.annotation.PostConstruct; +import net.sf.json.JSONObject; +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundResolvable; +import org.kohsuke.stapler.DataBoundSetter; +import org.kohsuke.stapler.StaplerRequest; + +public class DataBoundPostConstructTest implements DataBoundResolvable { + + static Object source(String label) { + return null; + } + + static void sink(Object o) {} + + static void test() { + new DataBoundPostConstructTest(source("constructor")); + new DataBoundPostConstructTest(null).setField(source("setter")); + } + + private Object field; + + @DataBoundConstructor + public DataBoundPostConstructTest(Object field) { + this.field = field; + } + + @DataBoundSetter + public void setField(Object field) { + this.field = field; + } + + private Object bindResolve(StaplerRequest request, JSONObject src) { + sink(this.field); // $ hasValueFlow=constructor hasValueFlow=setter + return null; + } + + @PostConstruct + private void post() { + sink(this.field); // $ hasValueFlow=constructor hasValueFlow=setter + } +} diff --git a/java/ql/test/library-tests/frameworks/stapler/HttpResponseTest.java b/java/ql/test/library-tests/frameworks/stapler/HttpResponseTest.java new file mode 100644 index 00000000000..d437d1a7de3 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/stapler/HttpResponseTest.java @@ -0,0 +1,26 @@ +import hudson.model.Descriptor; +import org.kohsuke.stapler.HttpResponse; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; + +public class HttpResponseTest { + + Object source() { + return null; + } + + void sink(Object o) {} + + private class MyDescriptor extends Descriptor { + public HttpResponse doTest() { + return (MyHttpResponse) source(); + } + } + + private class MyHttpResponse implements HttpResponse { + @Override + public void generateResponse(StaplerRequest p0, StaplerResponse p1, Object p2) { + sink(this); // $ hasValueFlow + } + } +} diff --git a/java/ql/test/library-tests/frameworks/stapler/options b/java/ql/test/library-tests/frameworks/stapler/options index 5b75976846a..52f4c738a88 100644 --- a/java/ql/test/library-tests/frameworks/stapler/options +++ b/java/ql/test/library-tests/frameworks/stapler/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/stapler-1.263:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/jaxen-1.2.0 \ No newline at end of file +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/stapler-1.263:${testdir}/../../../stubs/javax-servlet-2.5:${testdir}/../../../stubs/apache-commons-jelly-1.0.1:${testdir}/../../../stubs/apache-commons-fileupload-1.4:${testdir}/../../../stubs/saxon-xqj-9.x:${testdir}/../../../stubs/apache-commons-beanutils:${testdir}/../../../stubs/dom4j-2.1.1:${testdir}/../../../stubs/apache-commons-lang:${testdir}/../../../stubs/jaxen-1.2.0:${testdir}/../../../stubs/jenkins:${testdir}/../../../stubs/javax-annotation-api-1.3.2 \ No newline at end of file diff --git a/java/ql/test/stubs/javax-annotation-api-1.3.2/javax/annotation/PostConstruct.java b/java/ql/test/stubs/javax-annotation-api-1.3.2/javax/annotation/PostConstruct.java new file mode 100644 index 00000000000..a7fde6ae23b --- /dev/null +++ b/java/ql/test/stubs/javax-annotation-api-1.3.2/javax/annotation/PostConstruct.java @@ -0,0 +1,13 @@ +package javax.annotation; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Documented +@Retention(RUNTIME) +@Target(METHOD) +public @interface PostConstruct { +} diff --git a/java/ql/test/stubs/jenkins/hudson/model/Descriptor.java b/java/ql/test/stubs/jenkins/hudson/model/Descriptor.java new file mode 100644 index 00000000000..613ed31f665 --- /dev/null +++ b/java/ql/test/stubs/jenkins/hudson/model/Descriptor.java @@ -0,0 +1,5 @@ +package hudson.model; + +public abstract class Descriptor { + +} diff --git a/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundConstructor.java b/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundConstructor.java new file mode 100644 index 00000000000..6909171def8 --- /dev/null +++ b/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundConstructor.java @@ -0,0 +1,13 @@ +package org.kohsuke.stapler; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target(CONSTRUCTOR) +@Documented +public @interface DataBoundConstructor { +} diff --git a/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundResolvable.java b/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundResolvable.java new file mode 100644 index 00000000000..0fc9cffd0aa --- /dev/null +++ b/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundResolvable.java @@ -0,0 +1,4 @@ +package org.kohsuke.stapler; + +public interface DataBoundResolvable { +} diff --git a/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundSetter.java b/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundSetter.java new file mode 100644 index 00000000000..ff11084fcbd --- /dev/null +++ b/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/DataBoundSetter.java @@ -0,0 +1,14 @@ +package org.kohsuke.stapler; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({METHOD, FIELD}) +@Documented +public @interface DataBoundSetter { +} diff --git a/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/InjectedParameter.java b/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/InjectedParameter.java new file mode 100644 index 00000000000..1674e667233 --- /dev/null +++ b/java/ql/test/stubs/stapler-1.263/org/kohsuke/stapler/InjectedParameter.java @@ -0,0 +1,13 @@ +package org.kohsuke.stapler; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static java.lang.annotation.ElementType.ANNOTATION_TYPE;; + +@Retention(RUNTIME) +@Target(ANNOTATION_TYPE) +@Documented +public @interface InjectedParameter { +} From d071b463a3426af8186dc15c9aa131395e468217 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Jun 2023 14:14:37 +0100 Subject: [PATCH 095/364] Add failing tests for MaD with pointer content --- .../dataflow/ExternalFlow/completetest.ext.yml | 2 ++ .../semmle/go/dataflow/ExternalFlow/test.go | 16 ++++++++++++++++ .../vendor/github.com/nonexistent/test/stub.go | 3 +++ 3 files changed, 21 insertions(+) diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml index 79ca023562c..4ec8602daaf 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml @@ -22,7 +22,9 @@ extensions: - ["github.com/nonexistent/test", "", False, "GetMapKey", "", "", "Argument[0].MapKey", "ReturnValue", "value", "manual"] - ["github.com/nonexistent/test", "", False, "SetElement", "", "", "Argument[0]", "ReturnValue.Element", "value", "manual"] - ["github.com/nonexistent/test", "C", False, "Get", "", "", "Argument[-1].Field[github.com/nonexistent/test.C.F]", "ReturnValue", "value", "manual"] + - ["github.com/nonexistent/test", "C", False, "GetThroughPointer", "", "", "Argument[-1].Field[github.com/nonexistent/test.C.F]", "ReturnValue", "value", "manual"] - ["github.com/nonexistent/test", "C", False, "Set", "", "", "Argument[0]", "Argument[-1].Field[github.com/nonexistent/test.C.F]", "value", "manual"] + - ["github.com/nonexistent/test", "C", False, "SetThroughPointer", "", "", "Argument[0]", "Argument[-1].Field[github.com/nonexistent/test.C.F]", "value", "manual"] - addsTo: pack: codeql/go-all diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/test.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/test.go index a70b2868f58..0d92787b65c 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/test.go +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/test.go @@ -141,6 +141,22 @@ func simpleflow() { c4.Set("") b.Sink1(c4.Get()) // $ SPURIOUS: hasTaintFlow="call to Get" // because we currently don't clear content + cp1 := &test.C{""} + cp1.SetThroughPointer(a.Src1().(string)) + b.Sink1(cp1.F) // $ MISSING: hasTaintFlow="selection of F" + + cp2 := &test.C{a.Src1().(string)} + b.Sink1(cp2.GetThroughPointer()) // $ MISSING: hasTaintFlow="call to GetThroughPointer" + + cp3 := &test.C{""} + cp3.SetThroughPointer(a.Src1().(string)) + b.Sink1(cp3.GetThroughPointer()) // $ hasTaintFlow="call to GetThroughPointer" + + cp4 := &test.C{""} + cp4.SetThroughPointer(a.Src1().(string)) + cp4.SetThroughPointer("") + b.Sink1(cp4.GetThroughPointer()) // $ SPURIOUS: hasTaintFlow="call to GetThroughPointer" // because we currently don't clear content + arg1 := src arg2 := src arg3 := src diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/vendor/github.com/nonexistent/test/stub.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/vendor/github.com/nonexistent/test/stub.go index 2f13fce84e7..746f6ac9a6a 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/vendor/github.com/nonexistent/test/stub.go +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/vendor/github.com/nonexistent/test/stub.go @@ -67,3 +67,6 @@ type C struct { func (c C) Set(f string) {} func (c C) Get() string { return "" } + +func (c *C) SetThroughPointer(f string) {} +func (c *C) GetThroughPointer() string { return "" } From dd57d9fd550d0351a225d9ae5559d210285cf140 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Jun 2023 14:27:58 +0100 Subject: [PATCH 096/364] Add flowCheckNodeSpecific This allows individual languages to specify `FlowCheckNode`s, which break up the big step relation and make sure that those nodes appear in path summaries. --- go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll index 984c5ae2018..41341c6be5c 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll @@ -2021,7 +2021,8 @@ module Impl { FlowCheckNode() { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or - expectsContentCached(this.asNode(), _) + expectsContentCached(this.asNode(), _) or + flowCheckNodeSpecific(this.asNode()) } } From e0f7437d40630621b32b437338f8cd7fb9040202 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Jun 2023 14:29:56 +0100 Subject: [PATCH 097/364] Sync dataflow library --- cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 3 ++- .../lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 3 ++- .../lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 3 ++- .../ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 3 ++- .../lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll | 3 ++- ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll | 3 ++- swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll | 3 ++- 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 984c5ae2018..41341c6be5c 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -2021,7 +2021,8 @@ module Impl { FlowCheckNode() { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or - expectsContentCached(this.asNode(), _) + expectsContentCached(this.asNode(), _) or + flowCheckNodeSpecific(this.asNode()) } } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 984c5ae2018..41341c6be5c 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -2021,7 +2021,8 @@ module Impl { FlowCheckNode() { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or - expectsContentCached(this.asNode(), _) + expectsContentCached(this.asNode(), _) or + flowCheckNodeSpecific(this.asNode()) } } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 984c5ae2018..41341c6be5c 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -2021,7 +2021,8 @@ module Impl { FlowCheckNode() { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or - expectsContentCached(this.asNode(), _) + expectsContentCached(this.asNode(), _) or + flowCheckNodeSpecific(this.asNode()) } } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 984c5ae2018..41341c6be5c 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -2021,7 +2021,8 @@ module Impl { FlowCheckNode() { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or - expectsContentCached(this.asNode(), _) + expectsContentCached(this.asNode(), _) or + flowCheckNodeSpecific(this.asNode()) } } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index 984c5ae2018..41341c6be5c 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -2021,7 +2021,8 @@ module Impl { FlowCheckNode() { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or - expectsContentCached(this.asNode(), _) + expectsContentCached(this.asNode(), _) or + flowCheckNodeSpecific(this.asNode()) } } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll index 984c5ae2018..41341c6be5c 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll @@ -2021,7 +2021,8 @@ module Impl { FlowCheckNode() { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or - expectsContentCached(this.asNode(), _) + expectsContentCached(this.asNode(), _) or + flowCheckNodeSpecific(this.asNode()) } } diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll index 984c5ae2018..41341c6be5c 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll @@ -2021,7 +2021,8 @@ module Impl { FlowCheckNode() { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or - expectsContentCached(this.asNode(), _) + expectsContentCached(this.asNode(), _) or + flowCheckNodeSpecific(this.asNode()) } } From 5f72ce093594c5af730e16069d392a0d92d41751 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Jun 2023 14:36:45 +0100 Subject: [PATCH 098/364] Add stub implementations of flowCheckNodeSpecific --- .../semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll | 5 +++++ .../semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 5 +++++ .../semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll | 5 +++++ go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll | 5 +++++ .../semmle/code/java/dataflow/internal/DataFlowPrivate.qll | 5 +++++ .../semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 5 +++++ .../ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll | 5 +++++ .../lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll | 5 +++++ 8 files changed, 40 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index 115989e3dea..9b7b92f6fb8 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -235,6 +235,11 @@ class CastNode extends Node { CastNode() { none() } // stub implementation } +/** + * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + */ +predicate flowCheckNodeSpecific(Node n) { none() } + class DataFlowCallable = Function; class DataFlowExpr = Expr; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 33ff6f74775..dfd8fcbaccf 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -783,6 +783,11 @@ class CastNode extends Node { CastNode() { none() } // stub implementation } +/** + * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + */ +predicate flowCheckNodeSpecific(Node n) { none() } + /** * A function that may contain code or a variable that may contain itself. When * flow crosses from one _enclosing callable_ to another, the interprocedural diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index a3aed9f9097..27d35568e09 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -2147,6 +2147,11 @@ class CastNode extends Node { } } +/** + * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + */ +predicate flowCheckNodeSpecific(Node n) { none() } + class DataFlowExpr = DotNet::Expr; /** Holds if `e` is an expression that always has the same Boolean value `val`. */ diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll index ee146fc2aba..c014e89e397 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll @@ -228,6 +228,11 @@ class CastNode extends ExprNode { override ConversionExpr expr; } +/** + * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + */ +predicate flowCheckNodeSpecific(Node n) { none() } + class DataFlowExpr = Expr; private newtype TDataFlowType = diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index ea393dad0bf..eabfa3ecfc5 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -242,6 +242,11 @@ class CastNode extends ExprNode { CastNode() { this.getExpr() instanceof CastingExpr } } +/** + * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + */ +predicate flowCheckNodeSpecific(Node n) { none() } + private newtype TDataFlowCallable = TSrcCallable(Callable c) or TSummarizedCallable(SummarizedCallable c) or diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 7f907ca84e8..98c262375e1 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -497,6 +497,11 @@ class CastNode extends Node { CastNode() { readStep(_, _, this) or storeStep(_, _, this) } } +/** + * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + */ +predicate flowCheckNodeSpecific(Node n) { none() } + /** * Holds if `t1` and `t2` are compatible, that is, whether data can flow from * a node of type `t1` to a node of type `t2`. diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index 0fb0bac0462..313c76dfab7 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -1296,6 +1296,11 @@ class CastNode extends Node { } } +/** + * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + */ +predicate flowCheckNodeSpecific(Node n) { none() } + class DataFlowExpr = CfgNodes::ExprCfgNode; int accessPathLimit() { result = 5 } diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll index 02ae10b83af..b18f38cbb65 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll @@ -849,6 +849,11 @@ class CastNode extends Node { CastNode() { none() } } +/** + * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + */ +predicate flowCheckNodeSpecific(Node n) { none() } + class DataFlowExpr = Expr; class DataFlowParameter = ParamDecl; From ee185ae204691b78ff58358045717e19ae342912 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Jun 2023 14:41:16 +0100 Subject: [PATCH 099/364] Python: Move hack from CastNode into flowCheckNodeSpecific --- .../dataflow/new/internal/DataFlowPrivate.qll | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 98c262375e1..8df16662e07 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -486,6 +486,13 @@ class DataFlowType extends TDataFlowType { /** A node that performs a type cast. */ class CastNode extends Node { + CastNode() { none() } +} + +/** + * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + */ +predicate flowCheckNodeSpecific(Node n) { // We include read- and store steps here to force them to be // shown in path explanations. // This hack is necessary, because we have included some of these @@ -494,14 +501,9 @@ class CastNode extends Node { // We should revert this once, we can remove this steps from the // default taint steps; this should be possible once we have // implemented flow summaries and recursive content. - CastNode() { readStep(_, _, this) or storeStep(_, _, this) } + readStep(_, _, n) or storeStep(_, _, n) } -/** - * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. - */ -predicate flowCheckNodeSpecific(Node n) { none() } - /** * Holds if `t1` and `t2` are compatible, that is, whether data can flow from * a node of type `t1` to a node of type `t2`. From e34bcef2bd2527d7ab5c77af534fe3d0ab76bb72 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Jun 2023 14:41:58 +0100 Subject: [PATCH 100/364] Ruby: Move path summary visibility code into flowCheckNodeSpecific --- .../codeql/ruby/dataflow/internal/DataFlowPrivate.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index 313c76dfab7..6cabe899d5a 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -1290,16 +1290,16 @@ private import PostUpdateNodes /** A node that performs a type cast. */ class CastNode extends Node { - CastNode() { - // ensure that all variable assignments are included in the path graph - this.(SsaDefinitionExtNode).getDefinitionExt() instanceof Ssa::WriteDefinition - } + CastNode() { none() } } /** * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. */ -predicate flowCheckNodeSpecific(Node n) { none() } +predicate flowCheckNodeSpecific(Node n) { + // ensure that all variable assignments are included in the path graph + n.(SsaDefinitionExtNode).getDefinitionExt() instanceof Ssa::WriteDefinition +} class DataFlowExpr = CfgNodes::ExprCfgNode; From 3ff6d033d3def3e8781e8cd09bb2b471de580c1d Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Jun 2023 15:25:49 +0100 Subject: [PATCH 101/364] Rename to `neverSkipInPathGraph` --- .../lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 2 +- .../semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll | 5 +++-- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 2 +- .../semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 5 +++-- .../semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 2 +- .../semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll | 5 +++-- go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll | 2 +- go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll | 5 +++-- .../lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 2 +- .../semmle/code/java/dataflow/internal/DataFlowPrivate.qll | 5 +++-- .../lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll | 2 +- .../semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 5 +++-- ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll | 2 +- .../ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll | 5 +++-- swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll | 2 +- .../lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll | 5 +++-- 16 files changed, 32 insertions(+), 24 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 41341c6be5c..284fff191ae 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -2022,7 +2022,7 @@ module Impl { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or expectsContentCached(this.asNode(), _) or - flowCheckNodeSpecific(this.asNode()) + neverSkipInPathGraph(this.asNode()) } } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index 9b7b92f6fb8..b380748fb3c 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -236,9 +236,10 @@ class CastNode extends Node { } /** - * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + * Holds if `n` should never be skipped over in the `PathGraph` and in path + * explanations. */ -predicate flowCheckNodeSpecific(Node n) { none() } +predicate neverSkipInPathGraph(Node n) { none() } class DataFlowCallable = Function; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 41341c6be5c..284fff191ae 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -2022,7 +2022,7 @@ module Impl { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or expectsContentCached(this.asNode(), _) or - flowCheckNodeSpecific(this.asNode()) + neverSkipInPathGraph(this.asNode()) } } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index dfd8fcbaccf..ef006bbff0a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -784,9 +784,10 @@ class CastNode extends Node { } /** - * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + * Holds if `n` should never be skipped over in the `PathGraph` and in path + * explanations. */ -predicate flowCheckNodeSpecific(Node n) { none() } +predicate neverSkipInPathGraph(Node n) { none() } /** * A function that may contain code or a variable that may contain itself. When diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 41341c6be5c..284fff191ae 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -2022,7 +2022,7 @@ module Impl { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or expectsContentCached(this.asNode(), _) or - flowCheckNodeSpecific(this.asNode()) + neverSkipInPathGraph(this.asNode()) } } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 27d35568e09..c8287255f4f 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -2148,9 +2148,10 @@ class CastNode extends Node { } /** - * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + * Holds if `n` should never be skipped over in the `PathGraph` and in path + * explanations. */ -predicate flowCheckNodeSpecific(Node n) { none() } +predicate neverSkipInPathGraph(Node n) { none() } class DataFlowExpr = DotNet::Expr; diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll index 41341c6be5c..284fff191ae 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll @@ -2022,7 +2022,7 @@ module Impl { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or expectsContentCached(this.asNode(), _) or - flowCheckNodeSpecific(this.asNode()) + neverSkipInPathGraph(this.asNode()) } } diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll index c014e89e397..277c92703e7 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll @@ -229,9 +229,10 @@ class CastNode extends ExprNode { } /** - * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + * Holds if `n` should never be skipped over in the `PathGraph` and in path + * explanations. */ -predicate flowCheckNodeSpecific(Node n) { none() } +predicate neverSkipInPathGraph(Node n) { none() } class DataFlowExpr = Expr; diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 41341c6be5c..284fff191ae 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -2022,7 +2022,7 @@ module Impl { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or expectsContentCached(this.asNode(), _) or - flowCheckNodeSpecific(this.asNode()) + neverSkipInPathGraph(this.asNode()) } } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index eabfa3ecfc5..216523023d9 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -243,9 +243,10 @@ class CastNode extends ExprNode { } /** - * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + * Holds if `n` should never be skipped over in the `PathGraph` and in path + * explanations. */ -predicate flowCheckNodeSpecific(Node n) { none() } +predicate neverSkipInPathGraph(Node n) { none() } private newtype TDataFlowCallable = TSrcCallable(Callable c) or diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index 41341c6be5c..284fff191ae 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -2022,7 +2022,7 @@ module Impl { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or expectsContentCached(this.asNode(), _) or - flowCheckNodeSpecific(this.asNode()) + neverSkipInPathGraph(this.asNode()) } } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 8df16662e07..29504b6aa38 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -490,9 +490,10 @@ class CastNode extends Node { } /** - * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + * Holds if `n` should never be skipped over in the `PathGraph` and in path + * explanations. */ -predicate flowCheckNodeSpecific(Node n) { +predicate neverSkipInPathGraph(Node n) { // We include read- and store steps here to force them to be // shown in path explanations. // This hack is necessary, because we have included some of these diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll index 41341c6be5c..284fff191ae 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll @@ -2022,7 +2022,7 @@ module Impl { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or expectsContentCached(this.asNode(), _) or - flowCheckNodeSpecific(this.asNode()) + neverSkipInPathGraph(this.asNode()) } } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index 6cabe899d5a..f8469e99a23 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -1294,9 +1294,10 @@ class CastNode extends Node { } /** - * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + * Holds if `n` should never be skipped over in the `PathGraph` and in path + * explanations. */ -predicate flowCheckNodeSpecific(Node n) { +predicate neverSkipInPathGraph(Node n) { // ensure that all variable assignments are included in the path graph n.(SsaDefinitionExtNode).getDefinitionExt() instanceof Ssa::WriteDefinition } diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll index 41341c6be5c..284fff191ae 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll @@ -2022,7 +2022,7 @@ module Impl { castNode(this.asNode()) or clearsContentCached(this.asNode(), _) or expectsContentCached(this.asNode(), _) or - flowCheckNodeSpecific(this.asNode()) + neverSkipInPathGraph(this.asNode()) } } diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll index b18f38cbb65..c0f01a67df3 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll @@ -850,9 +850,10 @@ class CastNode extends Node { } /** - * Holds if `n` should be a FlowCheckNode, which will appear in path summaries. + * Holds if `n` should never be skipped over in the `PathGraph` and in path + * explanations. */ -predicate flowCheckNodeSpecific(Node n) { none() } +predicate neverSkipInPathGraph(Node n) { none() } class DataFlowExpr = Expr; From 74b39b42a181600c6f1f5f9dcb30535db4787856 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Jun 2023 15:47:25 +0100 Subject: [PATCH 102/364] Accept test changes --- .../semmle/go/dataflow/ExternalFlow/sinks.expected | 10 +++++++--- .../semmle/go/dataflow/ExternalFlow/srcs.expected | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.expected index 21199db73df..38dc380b55b 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.expected @@ -26,6 +26,10 @@ invalidModelRow | test.go:133:10:133:17 | call to Get | qltest | | test.go:137:10:137:17 | call to Get | qltest | | test.go:142:10:142:17 | call to Get | qltest | -| test.go:148:17:148:20 | arg1 | qltest | -| test.go:148:23:148:26 | arg2 | qltest | -| test.go:148:29:148:32 | arg3 | qltest | +| test.go:146:10:146:14 | selection of F | qltest | +| test.go:149:10:149:32 | call to GetThroughPointer | qltest | +| test.go:153:10:153:32 | call to GetThroughPointer | qltest | +| test.go:158:10:158:32 | call to GetThroughPointer | qltest | +| test.go:164:17:164:20 | arg1 | qltest | +| test.go:164:23:164:26 | arg2 | qltest | +| test.go:164:29:164:32 | arg3 | qltest | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.expected index 7b721110c67..2f1e3256778 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.expected @@ -17,3 +17,7 @@ invalidModelRow | test.go:132:15:132:22 | call to Src1 | qltest | | test.go:136:9:136:16 | call to Src1 | qltest | | test.go:140:9:140:16 | call to Src1 | qltest | +| test.go:145:24:145:31 | call to Src1 | qltest | +| test.go:148:17:148:24 | call to Src1 | qltest | +| test.go:152:24:152:31 | call to Src1 | qltest | +| test.go:156:24:156:31 | call to Src1 | qltest | From 053bf9a6680fd6156b3b4da43fe5624837ef81a5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 5 Jun 2023 21:22:33 +0100 Subject: [PATCH 103/364] Swift: Test the library. --- .../test/library-tests/regex/regex.expected | 2 ++ swift/ql/test/library-tests/regex/regex.ql | 30 ++++++++++++++++ swift/ql/test/library-tests/regex/regex.swift | 36 +++++++++---------- 3 files changed, 50 insertions(+), 18 deletions(-) create mode 100644 swift/ql/test/library-tests/regex/regex.expected create mode 100644 swift/ql/test/library-tests/regex/regex.ql diff --git a/swift/ql/test/library-tests/regex/regex.expected b/swift/ql/test/library-tests/regex/regex.expected new file mode 100644 index 00000000000..48de9172b36 --- /dev/null +++ b/swift/ql/test/library-tests/regex/regex.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/swift/ql/test/library-tests/regex/regex.ql b/swift/ql/test/library-tests/regex/regex.ql new file mode 100644 index 00000000000..902355dd78a --- /dev/null +++ b/swift/ql/test/library-tests/regex/regex.ql @@ -0,0 +1,30 @@ +import swift +import codeql.swift.regex.Regex +import TestUtilities.InlineExpectationsTest + +bindingset[s] +string quote(string s) { if s.matches("% %") then result = "\"" + s + "\"" else result = s } + +module RegexTest implements TestSig { + string getARelevantTag() { result = ["regex", "input"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(RegexEval eval, Expr regex | + eval.getRegex() = regex and + location = regex.getLocation() and + element = regex.toString() and + tag = "regex" and + value = quote(regex.toString()) + ) + or + exists(RegexEval eval, Expr input | + eval.getInput() = input and + location = input.getLocation() and + element = input.toString() and + tag = "input" and + value = quote(input.toString()) + ) + } +} + +import MakeTest diff --git a/swift/ql/test/library-tests/regex/regex.swift b/swift/ql/test/library-tests/regex/regex.swift index edf21a2b0a5..78955fe3670 100644 --- a/swift/ql/test/library-tests/regex/regex.swift +++ b/swift/ql/test/library-tests/regex/regex.swift @@ -102,36 +102,36 @@ func myRegexpMethodsTests() throws { // --- Regex --- - _ = try regex.firstMatch(in: input) - _ = try regex.prefixMatch(in: input) - _ = try regex.wholeMatch(in: input) + _ = try regex.firstMatch(in: input) // $ regex=regex input=input + _ = try regex.prefixMatch(in: input) // $ regex=regex input=input + _ = try regex.wholeMatch(in: input) // $ regex=regex input=input - // --- RangeReeplaceableCollection --- + // --- RangeReplaceableCollection --- var inputVar = input - inputVar.replace(regex, with: "")Var - _ = input.replacing(regex, with: "") - inputVar.trimPrefix(regex)Var + inputVar.replace(regex, with: "") // $ regex=regex input=&... + _ = input.replacing(regex, with: "") // $ regex=regex input=input + inputVar.trimPrefix(regex) // $ regex=regex input=&... // --- StringProtocol --- - _ = input.range(of: ".*", options: .regularExpression, range: nil, locale: nil) - _ = input.replacingOccurrences(of: ".*", with: "", options: .regularExpression) + _ = input.range(of: ".*", options: .regularExpression, range: nil, locale: nil) // $ MISSING: regex=regex input=input + _ = input.replacingOccurrences(of: ".*", with: "", options: .regularExpression) // $ MISSING: regex=regex input=input // --- NSRegularExpression --- let nsregex = try NSRegularExpression(pattern: ".*") - _ = nsregex.numberOfMatches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count)) - nsregex.enumerateMatches(in: input, range: NSMakeRange(0, input.utf16.count), using: {a, b, c in } ) - _ = nsregex.matches(in: input, range: NSMakeRange(0, input.utf16.count)) - _ = nsregex.firstMatch(in: input, range: NSMakeRange(0, input.utf16.count)) - _ = nsregex.rangeOfFirstMatch(in: input, range: NSMakeRange(0, input.utf16.count)) - _ = nsregex.replaceMatches(in: NSMutableString(string: input), range: NSMakeRange(0, input.utf16.count), withTemplate: "") - _ = nsregex.stringByReplacingMatches(in: input, range: NSMakeRange(0, input.utf16.count), withTemplate: "") + _ = nsregex.numberOfMatches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count)) // $ regex=nsregex input=input + nsregex.enumerateMatches(in: input, range: NSMakeRange(0, input.utf16.count), using: {a, b, c in } ) // $ regex=nsregex input=input + _ = nsregex.matches(in: input, range: NSMakeRange(0, input.utf16.count)) // $ regex=nsregex input=input + _ = nsregex.firstMatch(in: input, range: NSMakeRange(0, input.utf16.count)) // $ regex=nsregex input=input + _ = nsregex.rangeOfFirstMatch(in: input, range: NSMakeRange(0, input.utf16.count)) // $ regex=nsregex input=input + _ = nsregex.replaceMatches(in: NSMutableString(string: input), range: NSMakeRange(0, input.utf16.count), withTemplate: "") // $ regex=nsregex input="call to NSString.init(string:)" + _ = nsregex.stringByReplacingMatches(in: input, range: NSMakeRange(0, input.utf16.count), withTemplate: "") // $ regex=nsregex input=input // --- NSString --- let inputNS = NSString(string: "abcdef") - _ = inputNS.range(of: "*", options: .regularExpression) - _ = inputNS.replacingOccurrences(of: ".*", with: "", options: .regularExpression, range: NSMakeRange(0, inputNS.length)) + _ = inputNS.range(of: "*", options: .regularExpression) // $ MISSING: regex=nsregex input=inputNS + _ = inputNS.replacingOccurrences(of: ".*", with: "", options: .regularExpression, range: NSMakeRange(0, inputNS.length)) // $ MISSING: regex=nsregex input=inputNS } From f7860a3ce5e4aa0884abbf09cd00844dab5f4278 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:01:21 +0100 Subject: [PATCH 104/364] Swift: Add regular expressions to SummaryStats.ql. --- swift/ql/src/queries/Summary/SummaryStats.ql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/swift/ql/src/queries/Summary/SummaryStats.ql b/swift/ql/src/queries/Summary/SummaryStats.ql index 444c4da2ca2..b6789a108be 100644 --- a/swift/ql/src/queries/Summary/SummaryStats.ql +++ b/swift/ql/src/queries/Summary/SummaryStats.ql @@ -11,6 +11,7 @@ import codeql.swift.dataflow.FlowSources import codeql.swift.security.SensitiveExprs import codeql.swift.dataflow.DataFlow import codeql.swift.dataflow.TaintTracking +import codeql.swift.regex.Regex /** * A taint configuration for tainted data reaching any node. @@ -50,6 +51,8 @@ predicate statistic(string what, string value) { what = "Dataflow nodes (tainted)" and value = taintedNodesCount().toString() or what = "Taint reach (per million nodes)" and value = taintReach().toString() + or + what = "Regular expression evals" and value = count(RegexEval e).toString() } from string what, string value From 9601134ec0f675e6f9eb88fff00b6f8231d59e1b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 5 Jun 2023 21:19:49 +0100 Subject: [PATCH 105/364] Swift: Create library test cases for REDOS vulnerable regexs. --- .../library-tests/regex/redos_variants.swift | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 swift/ql/test/library-tests/regex/redos_variants.swift diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift new file mode 100644 index 00000000000..4bd1224d89a --- /dev/null +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -0,0 +1,50 @@ + +// --- stubs --- + +struct URL { + init?(string: String) {} +} + +struct AnyRegexOutput { +} + +protocol RegexComponent { +} + +struct Regex : RegexComponent { + struct Match { + } + + init(_ pattern: String) throws where Output == AnyRegexOutput { } + + func firstMatch(in string: String) throws -> Regex.Match? { return nil} + + typealias RegexOutput = Output +} + +extension String { + init(contentsOf: URL) { + let data = "" + self.init(data) + } +} + +// --- tests --- + +func myRegexpVariantsTests(myUrl: URL) throws { + let tainted = String(contentsOf: myUrl) // tainted + let untainted = "abcdef" + + _ = try Regex(".*").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted + + _ = try Regex("a*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted + _ = try Regex("(a*)b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted + _ = try Regex("(a)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted + _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted MISSING: redos-vulnerable= + _ = try Regex("((a*)*b)").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted MISSING: redos-vulnerable= + + _ = try Regex("(a|aa?)b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted + _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted MISSING: redos-vulnerable= + + // TODO: test more variant expressions. +} From 8ec377997dc9f2a0b4c5959169225a2a0c705a29 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 6 Jun 2023 18:21:47 +0100 Subject: [PATCH 106/364] Swift: Copy some library files from Ruby (as advised). --- .../lib/codeql/swift/regex/RegexTreeView.qll | 1235 +++++++++++++++++ .../swift/regex/internal/ParseRegex.qll | 1037 ++++++++++++++ 2 files changed, 2272 insertions(+) create mode 100644 swift/ql/lib/codeql/swift/regex/RegexTreeView.qll create mode 100644 swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll diff --git a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll new file mode 100644 index 00000000000..51df1700881 --- /dev/null +++ b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll @@ -0,0 +1,1235 @@ +/** Provides a class hierarchy corresponding to a parse tree of regular expressions. */ + +private import internal.ParseRegExp +private import codeql.util.Numbers +private import codeql.ruby.ast.Literal as Ast +private import codeql.Locations +private import codeql.regex.nfa.NfaUtils as NfaUtils +private import codeql.regex.RegexTreeView +// exporting as RegexTreeView, and in the top-level scope. +import Impl as RegexTreeView +import Impl + +/** Gets the parse tree resulting from parsing `re`, if such has been constructed. */ +RegExpTerm getParsedRegExp(Ast::RegExpLiteral re) { + result.getRegExp() = re and result.isRootTerm() +} + +/** + * An element containing a regular expression term, that is, either + * a string literal (parsed as a regular expression) + * or another regular expression term. + * + * For sequences and alternations, we require at least one child. + * Otherwise, we wish to represent the term differently. + * This avoids multiple representations of the same term. + */ +private newtype TRegExpParent = + /** A string literal used as a regular expression */ + TRegExpLiteral(RegExp re) or + /** A quantified term */ + TRegExpQuantifier(RegExp re, int start, int end) { re.qualifiedItem(start, end, _, _) } or + /** A sequence term */ + TRegExpSequence(RegExp re, int start, int end) { re.sequence(start, end) } or + /** An alternation term */ + TRegExpAlt(RegExp re, int start, int end) { re.alternation(start, end) } or + /** A character class term */ + TRegExpCharacterClass(RegExp re, int start, int end) { re.charSet(start, end) } or + /** A character range term */ + TRegExpCharacterRange(RegExp re, int start, int end) { re.charRange(_, start, _, _, end) } or + /** A group term */ + TRegExpGroup(RegExp re, int start, int end) { re.group(start, end) } or + /** A special character */ + TRegExpSpecialChar(RegExp re, int start, int end) { re.specialCharacter(start, end, _) } or + /** A normal character */ + TRegExpNormalChar(RegExp re, int start, int end) { + re.normalCharacterSequence(start, end) + or + re.escapedCharacter(start, end) and + not re.specialCharacter(start, end, _) + } or + /** A back reference */ + TRegExpBackRef(RegExp re, int start, int end) { re.backreference(start, end) } or + /** A named character property */ + TRegExpNamedCharacterProperty(RegExp re, int start, int end) { + re.namedCharacterProperty(start, end, _) + } + +/** An implementation that statisfies the RegexTreeView signature. */ +private module Impl implements RegexTreeViewSig { + /** + * An element containing a regular expression term, that is, either + * a string literal (parsed as a regular expression) + * or another regular expression term. + */ + class RegExpParent extends TRegExpParent { + /** Gets a textual representation of this element. */ + string toString() { result = "RegExpParent" } + + /** Gets the `i`th child term. */ + RegExpTerm getChild(int i) { none() } + + /** Gets a child term . */ + final RegExpTerm getAChild() { result = this.getChild(_) } + + /** Gets the number of child terms. */ + int getNumChild() { result = count(this.getAChild()) } + + /** Gets the last child term of this element. */ + RegExpTerm getLastChild() { result = this.getChild(this.getNumChild() - 1) } + + /** + * Gets the name of a primary CodeQL class to which this regular + * expression term belongs. + */ + string getAPrimaryQlClass() { result = "RegExpParent" } + + /** + * Gets a comma-separated list of the names of the primary CodeQL classes to + * which this regular expression term belongs. + */ + final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } + } + + /** A string literal used as a regular expression */ + class RegExpLiteral extends TRegExpLiteral, RegExpParent { + RegExp re; + + RegExpLiteral() { this = TRegExpLiteral(re) } + + override RegExpTerm getChild(int i) { + i = 0 and result.getRegExp() = re and result.isRootTerm() + } + + /** Holds if dot, `.`, matches all characters, including newlines. */ + predicate isDotAll() { re.isDotAll() } + + /** Holds if this regex matching is case-insensitive for this regex. */ + predicate isIgnoreCase() { re.isIgnoreCase() } + + /** Get a string representing all modes for this regex. */ + string getFlags() { result = re.getFlags() } + + /** Gets the primary QL class for this regex. */ + override string getAPrimaryQlClass() { result = "RegExpLiteral" } + } + + /** + * A regular expression term, that is, a syntactic part of a regular expression. + */ + class RegExpTerm extends RegExpParent { + RegExp re; + int start; + int end; + + RegExpTerm() { + this = TRegExpAlt(re, start, end) + or + this = TRegExpBackRef(re, start, end) + or + this = TRegExpCharacterClass(re, start, end) + or + this = TRegExpCharacterRange(re, start, end) + or + this = TRegExpNormalChar(re, start, end) + or + this = TRegExpGroup(re, start, end) + or + this = TRegExpQuantifier(re, start, end) + or + this = TRegExpSequence(re, start, end) and + exists(seqChild(re, start, end, 1)) // if a sequence does not have more than one element, it should be treated as that element instead. + or + this = TRegExpSpecialChar(re, start, end) + or + this = TRegExpNamedCharacterProperty(re, start, end) + } + + /** + * Gets the outermost term of this regular expression. + */ + RegExpTerm getRootTerm() { + this.isRootTerm() and result = this + or + result = this.getParent().(RegExpTerm).getRootTerm() + } + + /** + * Holds if this term is part of a string literal + * that is interpreted as a regular expression. + */ + predicate isUsedAsRegExp() { any() } + + /** + * Holds if this is the root term of a regular expression. + */ + predicate isRootTerm() { start = 0 and end = re.getText().length() } + + override RegExpTerm getChild(int i) { + result = this.(RegExpAlt).getChild(i) + or + result = this.(RegExpBackRef).getChild(i) + or + result = this.(RegExpCharacterClass).getChild(i) + or + result = this.(RegExpCharacterRange).getChild(i) + or + result = this.(RegExpNormalChar).getChild(i) + or + result = this.(RegExpGroup).getChild(i) + or + result = this.(RegExpQuantifier).getChild(i) + or + result = this.(RegExpSequence).getChild(i) + or + result = this.(RegExpSpecialChar).getChild(i) + or + result = this.(RegExpNamedCharacterProperty).getChild(i) + } + + /** + * Gets the parent term of this regular expression term, or the + * regular expression literal if this is the root term. + */ + RegExpParent getParent() { result.getAChild() = this } + + /** Gets the associated `RegExp`. */ + RegExp getRegExp() { result = re } + + /** Gets the offset at which this term starts. */ + int getStart() { result = start } + + /** Gets the offset at which this term ends. */ + int getEnd() { result = end } + + override string toString() { result = re.getText().substring(start, end) } + + /** + * Gets the location of the surrounding regex, as locations inside the regex do not exist. + * To get location information corresponding to the term inside the regex, + * use `hasLocationInfo`. + */ + Location getLocation() { result = re.getLocation() } + + pragma[noinline] + private predicate componentHasLocationInfo( + int i, string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + re.getComponent(i) + .getLocation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Holds if this term is found at the specified location offsets. */ + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + exists(int re_start | + this.componentHasLocationInfo(0, filepath, startline, re_start, _, _) and + this.componentHasLocationInfo(re.getNumberOfComponents() - 1, filepath, _, _, endline, _) and + startcolumn = re_start + start and + endcolumn = re_start + end - 1 + ) + } + + /** Gets the file in which this term is found. */ + File getFile() { result = this.getLocation().getFile() } + + /** Gets the raw source text of this term. */ + string getRawValue() { result = this.toString() } + + /** Gets the string literal in which this term is found. */ + RegExpLiteral getLiteral() { result = TRegExpLiteral(re) } + + /** Gets the regular expression term that is matched (textually) before this one, if any. */ + RegExpTerm getPredecessor() { + exists(RegExpTerm parent | parent = this.getParent() | + result = parent.(RegExpSequence).previousElement(this) + or + not exists(parent.(RegExpSequence).previousElement(this)) and + not parent instanceof RegExpSubPattern and + result = parent.getPredecessor() + ) + } + + /** Gets the regular expression term that is matched (textually) after this one, if any. */ + RegExpTerm getSuccessor() { + exists(RegExpTerm parent | parent = this.getParent() | + result = parent.(RegExpSequence).nextElement(this) + or + not exists(parent.(RegExpSequence).nextElement(this)) and + not parent instanceof RegExpSubPattern and + result = parent.getSuccessor() + ) + } + + /** + * Gets the single string this regular-expression term matches. + * + * This predicate is only defined for (sequences/groups of) constant regular + * expressions. In particular, terms involving zero-width assertions like `^` + * or `\b` are not considered to have a constant value. + * + * Note that this predicate does not take flags of the enclosing + * regular-expression literal into account. + */ + string getConstantValue() { none() } + + /** + * Gets a string that is matched by this regular-expression term. + */ + string getAMatchedString() { result = this.getConstantValue() } + + /** Gets the primary QL class for this term. */ + override string getAPrimaryQlClass() { result = "RegExpTerm" } + + /** Holds if this regular expression term can match the empty string. */ + predicate isNullable() { none() } + } + + /** + * A quantified regular expression term. + * + * Example: + * + * ``` + * ((ECMA|Java)[sS]cript)* + * ``` + */ + class RegExpQuantifier extends RegExpTerm, TRegExpQuantifier { + int part_end; + boolean may_repeat_forever; + + RegExpQuantifier() { + this = TRegExpQuantifier(re, start, end) and + re.qualifiedPart(start, part_end, end, _, may_repeat_forever) + } + + override RegExpTerm getChild(int i) { + i = 0 and + result.getRegExp() = re and + result.getStart() = start and + result.getEnd() = part_end + } + + /** Hols if this term may match an unlimited number of times. */ + predicate mayRepeatForever() { may_repeat_forever = true } + + /** Gets the qualifier for this term. That is e.g "?" for "a?". */ + string getQualifier() { result = re.getText().substring(part_end, end) } + + override string getAPrimaryQlClass() { result = "RegExpQuantifier" } + } + + /** + * A regular expression term that permits unlimited repetitions. + */ + class InfiniteRepetitionQuantifier extends RegExpQuantifier { + InfiniteRepetitionQuantifier() { this.mayRepeatForever() } + + override string getAPrimaryQlClass() { result = "InfiniteRepetitionQuantifier" } + } + + /** + * A star-quantified term. + * + * Example: + * + * ``` + * \w* + * ``` + */ + class RegExpStar extends InfiniteRepetitionQuantifier { + RegExpStar() { this.getQualifier().charAt(0) = "*" } + + override string getAPrimaryQlClass() { result = "RegExpStar" } + + override predicate isNullable() { any() } + } + + /** + * A plus-quantified term. + * + * Example: + * + * ``` + * \w+ + * ``` + */ + class RegExpPlus extends InfiniteRepetitionQuantifier { + RegExpPlus() { this.getQualifier().charAt(0) = "+" } + + override string getAPrimaryQlClass() { result = "RegExpPlus" } + + override predicate isNullable() { this.getAChild().isNullable() } + } + + /** + * An optional term. + * + * Example: + * + * ``` + * ;? + * ``` + */ + class RegExpOpt extends RegExpQuantifier { + RegExpOpt() { this.getQualifier().charAt(0) = "?" } + + override string getAPrimaryQlClass() { result = "RegExpOpt" } + + override predicate isNullable() { any() } + } + + /** + * A range-quantified term + * + * Examples: + * + * ``` + * \w{2,4} + * \w{2,} + * \w{2} + * ``` + */ + class RegExpRange extends RegExpQuantifier { + string upper; + string lower; + + RegExpRange() { re.multiples(part_end, end, lower, upper) } + + override string getAPrimaryQlClass() { result = "RegExpRange" } + + /** Gets the string defining the upper bound of this range, if any. */ + string getUpper() { result = upper } + + /** Gets the string defining the lower bound of this range, if any. */ + string getLower() { result = lower } + + /** + * Gets the upper bound of the range, if any. + * + * If there is no upper bound, any number of repetitions is allowed. + * For a term of the form `r{lo}`, both the lower and the upper bound + * are `lo`. + */ + int getUpperBound() { result = this.getUpper().toInt() } + + /** Gets the lower bound of the range. */ + int getLowerBound() { result = this.getLower().toInt() } + + override predicate isNullable() { this.getAChild().isNullable() or this.getLowerBound() = 0 } + } + + /** + * A sequence term. + * + * Example: + * + * ``` + * (ECMA|Java)Script + * ``` + * + * This is a sequence with the elements `(ECMA|Java)` and `Script`. + */ + class RegExpSequence extends RegExpTerm, TRegExpSequence { + RegExpSequence() { + this = TRegExpSequence(re, start, end) and + exists(seqChild(re, start, end, 1)) // if a sequence does not have more than one element, it should be treated as that element instead. + } + + override RegExpTerm getChild(int i) { result = seqChild(re, start, end, i) } + + /** Gets the element preceding `element` in this sequence. */ + RegExpTerm previousElement(RegExpTerm element) { element = this.nextElement(result) } + + /** Gets the element following `element` in this sequence. */ + RegExpTerm nextElement(RegExpTerm element) { + exists(int i | + element = this.getChild(i) and + result = this.getChild(i + 1) + ) + } + + override string getConstantValue() { result = this.getConstantValue(0) } + + /** + * Gets the single string matched by the `i`th child and all following + * children of this sequence, if any. + */ + private string getConstantValue(int i) { + i = this.getNumChild() and + result = "" + or + result = this.getChild(i).getConstantValue() + this.getConstantValue(i + 1) + } + + override string getAPrimaryQlClass() { result = "RegExpSequence" } + + override predicate isNullable() { + forall(RegExpTerm child | child = this.getAChild() | child.isNullable()) + } + } + + pragma[nomagic] + private int seqChildEnd(RegExp re, int start, int end, int i) { + result = seqChild(re, start, end, i).getEnd() + } + + // moved out so we can use it in the charpred + private RegExpTerm seqChild(RegExp re, int start, int end, int i) { + re.sequence(start, end) and + ( + i = 0 and + result.getRegExp() = re and + result.getStart() = start and + exists(int itemEnd | + re.item(start, itemEnd) and + result.getEnd() = itemEnd + ) + or + i > 0 and + result.getRegExp() = re and + exists(int itemStart | itemStart = seqChildEnd(re, start, end, i - 1) | + result.getStart() = itemStart and + re.item(itemStart, result.getEnd()) + ) + ) + } + + /** + * An alternative term, that is, a term of the form `a|b`. + * + * Example: + * + * ``` + * ECMA|Java + * ``` + */ + class RegExpAlt extends RegExpTerm, TRegExpAlt { + RegExpAlt() { this = TRegExpAlt(re, start, end) } + + override RegExpTerm getChild(int i) { + i = 0 and + result.getRegExp() = re and + result.getStart() = start and + exists(int part_end | + re.alternationOption(start, end, start, part_end) and + result.getEnd() = part_end + ) + or + i > 0 and + result.getRegExp() = re and + exists(int part_start | + part_start = this.getChild(i - 1).getEnd() + 1 // allow for the | + | + result.getStart() = part_start and + re.alternationOption(start, end, part_start, result.getEnd()) + ) + } + + /** Gets an alternative of this term. */ + RegExpTerm getAlternative() { result = this.getAChild() } + + override string getAMatchedString() { result = this.getAlternative().getAMatchedString() } + + override string getAPrimaryQlClass() { result = "RegExpAlt" } + + override predicate isNullable() { this.getAChild().isNullable() } + } + + /** + * A character escape in a regular expression. + * + * Example: + * + * ``` + * \. + * ``` + */ + class RegExpCharEscape = RegExpEscape; + + /** + * An escaped regular expression term, that is, a regular expression + * term starting with a backslash, which is not a backreference. + * + * Example: + * + * ``` + * \. + * \w + * ``` + */ + class RegExpEscape extends RegExpNormalChar { + RegExpEscape() { re.escapedCharacter(start, end) } + + /** + * Gets the name of the escaped; for example, `w` for `\w`. + * TODO: Handle named escapes. + */ + override string getValue() { + not this.isUnicode() and + this.isIdentityEscape() and + result = this.getUnescaped() + or + this.getUnescaped() = "n" and result = "\n" + or + this.getUnescaped() = "r" and result = "\r" + or + this.getUnescaped() = "t" and result = "\t" + or + this.getUnescaped() = "f" and result = 12.toUnicode() + or + this.getUnescaped() = "v" and result = 11.toUnicode() + or + this.isUnicode() and + result = this.getUnicode() + } + + /** Holds if this terms name is given by the part following the escape character. */ + predicate isIdentityEscape() { + not this.getUnescaped() in ["n", "r", "t", "f", "v"] and not this.isUnicode() + } + + override string getAPrimaryQlClass() { result = "RegExpEscape" } + + /** Gets the part of the term following the escape character. That is e.g. "w" if the term is "\w". */ + string getUnescaped() { result = this.getText().suffix(1) } + + /** + * Gets the text for this escape. That is e.g. "\w". + */ + private string getText() { result = re.getText().substring(start, end) } + + /** + * Holds if this is a unicode escape. + */ + private predicate isUnicode() { this.getText().prefix(2) = ["\\u", "\\U"] } + + /** + * Gets the unicode char for this escape. + * E.g. for `\u0061` this returns "a". + */ + private string getUnicode() { + this.isUnicode() and + result = parseHexInt(this.getText().suffix(2)).toUnicode() + } + } + + /** + * A word boundary, that is, a regular expression term of the form `\b`. + */ + class RegExpWordBoundary extends RegExpSpecialChar { + RegExpWordBoundary() { this.getChar() = "\\b" } + + override predicate isNullable() { none() } + } + + /** + * A non-word boundary, that is, a regular expression term of the form `\B`. + */ + class RegExpNonWordBoundary extends RegExpSpecialChar { + RegExpNonWordBoundary() { this.getChar() = "\\B" } + + override string getAPrimaryQlClass() { result = "RegExpNonWordBoundary" } + } + + /** + * A character class escape in a regular expression. + * That is, an escaped character that denotes multiple characters. + * + * Examples: + * + * ``` + * \w + * \S + * ``` + */ + class RegExpCharacterClassEscape extends RegExpEscape { + RegExpCharacterClassEscape() { this.getValue() in ["d", "D", "s", "S", "w", "W", "h", "H"] } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpCharacterClassEscape" } + + override predicate isNullable() { none() } + } + + /** + * A character class in a regular expression. + * + * Examples: + * + * ```rb + * /[a-fA-F0-9]/ + * /[^abc]/ + * ``` + */ + class RegExpCharacterClass extends RegExpTerm, TRegExpCharacterClass { + RegExpCharacterClass() { this = TRegExpCharacterClass(re, start, end) } + + /** Holds if this character class is inverted, matching the opposite of its content. */ + predicate isInverted() { re.getChar(start + 1) = "^" } + + /** Holds if this character class can match anything. */ + predicate isUniversalClass() { + // [^] + this.isInverted() and not exists(this.getAChild()) + or + // [\w\W] and similar + not this.isInverted() and + exists(string cce1, string cce2 | + cce1 = this.getAChild().(RegExpCharacterClassEscape).getValue() and + cce2 = this.getAChild().(RegExpCharacterClassEscape).getValue() + | + cce1 != cce2 and cce1.toLowerCase() = cce2.toLowerCase() + ) + } + + override RegExpTerm getChild(int i) { + i = 0 and + result.getRegExp() = re and + exists(int itemStart, int itemEnd | + result.getStart() = itemStart and + re.charSetStart(start, itemStart) and + re.charSetChild(start, itemStart, itemEnd) and + result.getEnd() = itemEnd + ) + or + i > 0 and + result.getRegExp() = re and + exists(int itemStart | itemStart = this.getChild(i - 1).getEnd() | + result.getStart() = itemStart and + re.charSetChild(start, itemStart, result.getEnd()) + ) + } + + override string getAMatchedString() { + not this.isInverted() and result = this.getAChild().getAMatchedString() + } + + override string getAPrimaryQlClass() { result = "RegExpCharacterClass" } + + override predicate isNullable() { none() } + } + + /** + * A character range in a character class in a regular expression. + * + * Example: + * + * ``` + * a-z + * ``` + */ + class RegExpCharacterRange extends RegExpTerm, TRegExpCharacterRange { + int lower_end; + int upper_start; + + RegExpCharacterRange() { + this = TRegExpCharacterRange(re, start, end) and + re.charRange(_, start, lower_end, upper_start, end) + } + + /** Holds if this range goes from `lo` to `hi`, in effect is `lo-hi`. */ + predicate isRange(string lo, string hi) { + lo = re.getText().substring(start, lower_end) and + hi = re.getText().substring(upper_start, end) + } + + override RegExpTerm getChild(int i) { + i = 0 and + result.getRegExp() = re and + result.getStart() = start and + result.getEnd() = lower_end + or + i = 1 and + result.getRegExp() = re and + result.getStart() = upper_start and + result.getEnd() = end + } + + override string getAPrimaryQlClass() { result = "RegExpCharacterRange" } + + override predicate isNullable() { none() } + } + + /** + * A normal character in a regular expression, that is, a character + * without special meaning. This includes escaped characters. + * + * Examples: + * ``` + * t + * \t + * ``` + */ + additional class RegExpNormalChar extends RegExpTerm, TRegExpNormalChar { + RegExpNormalChar() { this = TRegExpNormalChar(re, start, end) } + + /** + * Holds if this constant represents a valid Unicode character (as opposed + * to a surrogate code point that does not correspond to a character by itself.) + */ + predicate isCharacter() { any() } + + /** Gets the string representation of the char matched by this term. */ + string getValue() { result = re.getText().substring(start, end) } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpNormalChar" } + } + + /** + * A constant regular expression term, that is, a regular expression + * term matching a single string. Currently, this will always be a single character. + * + * Example: + * + * ``` + * a + * ``` + */ + class RegExpConstant extends RegExpTerm { + string value; + + RegExpConstant() { + this = TRegExpNormalChar(re, start, end) and + not this instanceof RegExpCharacterClassEscape and + // exclude chars in qualifiers + // TODO: push this into regex library + not exists(int qstart, int qend | re.qualifiedPart(_, qstart, qend, _, _) | + qstart <= start and end <= qend + ) and + value = this.(RegExpNormalChar).getValue() + or + this = TRegExpSpecialChar(re, start, end) and + re.inCharSet(start) and + value = this.(RegExpSpecialChar).getChar() + } + + /** + * Holds if this constant represents a valid Unicode character (as opposed + * to a surrogate code point that does not correspond to a character by itself.) + */ + predicate isCharacter() { any() } + + /** Gets the string matched by this constant term. */ + string getValue() { result = value } + + override RegExpTerm getChild(int i) { none() } + + override string getConstantValue() { result = this.getValue() } + + override string getAPrimaryQlClass() { result = "RegExpConstant" } + + override predicate isNullable() { none() } + } + + /** + * A grouped regular expression. + * + * Examples: + * + * ``` + * (ECMA|Java) + * (?:ECMA|Java) + * (?['"]) + * ``` + */ + class RegExpGroup extends RegExpTerm, TRegExpGroup { + RegExpGroup() { this = TRegExpGroup(re, start, end) } + + /** + * Gets the index of this capture group within the enclosing regular + * expression literal. + * + * For example, in the regular expression `/((a?).)(?:b)/`, the + * group `((a?).)` has index 1, the group `(a?)` nested inside it + * has index 2, and the group `(?:b)` has no index, since it is + * not a capture group. + */ + int getNumber() { result = re.getGroupNumber(start, end) } + + /** Holds if this is a capture group. */ + predicate isCapture() { exists(this.getNumber()) } + + /** Holds if this is a named capture group. */ + predicate isNamed() { exists(this.getName()) } + + /** Gets the name of this capture group, if any. */ + string getName() { result = re.getGroupName(start, end) } + + override RegExpTerm getChild(int i) { + result.getRegExp() = re and + i = 0 and + re.groupContents(start, end, result.getStart(), result.getEnd()) + } + + override string getConstantValue() { result = this.getAChild().getConstantValue() } + + override string getAMatchedString() { result = this.getAChild().getAMatchedString() } + + override string getAPrimaryQlClass() { result = "RegExpGroup" } + + override predicate isNullable() { this.getAChild().isNullable() } + } + + /** + * A special character in a regular expression. + * + * Examples: + * ``` + * ^ + * $ + * . + * ``` + */ + additional class RegExpSpecialChar extends RegExpTerm, TRegExpSpecialChar { + string char; + + RegExpSpecialChar() { + this = TRegExpSpecialChar(re, start, end) and + re.specialCharacter(start, end, char) + } + + /** + * Holds if this constant represents a valid Unicode character (as opposed + * to a surrogate code point that does not correspond to a character by itself.) + */ + predicate isCharacter() { any() } + + /** Gets the char for this term. */ + string getChar() { result = char } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpSpecialChar" } + } + + /** + * A dot regular expression. + * + * Example: + * + * ``` + * . + * ``` + */ + class RegExpDot extends RegExpSpecialChar { + RegExpDot() { this.getChar() = "." } + + override string getAPrimaryQlClass() { result = "RegExpDot" } + + override predicate isNullable() { none() } + } + + /** + * A term that matches a specific position between characters in the string. + * + * Example: + * + * ``` + * \A + * ``` + */ + class RegExpAnchor extends RegExpSpecialChar { + RegExpAnchor() { this.getChar() = ["^", "$", "\\A", "\\Z", "\\z"] } + + override string getAPrimaryQlClass() { result = "RegExpAnchor" } + } + + /** + * A dollar assertion `$` or `\Z` matching the end of a line. + * + * Example: + * + * ``` + * $ + * ``` + */ + class RegExpDollar extends RegExpAnchor { + RegExpDollar() { this.getChar() = ["$", "\\Z", "\\z"] } + + override string getAPrimaryQlClass() { result = "RegExpDollar" } + + override predicate isNullable() { any() } + } + + /** + * A caret assertion `^` or `\A` matching the beginning of a line. + * + * Example: + * + * ``` + * ^ + * ``` + */ + class RegExpCaret extends RegExpAnchor { + RegExpCaret() { this.getChar() = ["^", "\\A"] } + + override string getAPrimaryQlClass() { result = "RegExpCaret" } + + override predicate isNullable() { any() } + } + + /** + * A zero-width match, that is, either an empty group or an assertion. + * + * Examples: + * ``` + * () + * (?=\w) + * ``` + */ + additional class RegExpZeroWidthMatch extends RegExpGroup { + RegExpZeroWidthMatch() { re.zeroWidthMatch(start, end) } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpZeroWidthMatch" } + + override predicate isNullable() { any() } + } + + /** + * A zero-width lookahead or lookbehind assertion. + * + * Examples: + * + * ``` + * (?=\w) + * (?!\n) + * (?<=\.) + * (?` + * in a regular expression. + * + * Examples: + * + * ``` + * \1 + * (?P=quote) + * ``` + */ + class RegExpBackRef extends RegExpTerm, TRegExpBackRef { + RegExpBackRef() { this = TRegExpBackRef(re, start, end) } + + /** + * Gets the number of the capture group this back reference refers to, if any. + */ + int getNumber() { result = re.getBackRefNumber(start, end) } + + /** + * Gets the name of the capture group this back reference refers to, if any. + */ + string getName() { result = re.getBackRefName(start, end) } + + /** Gets the capture group this back reference refers to. */ + RegExpGroup getGroup() { + result.getLiteral() = this.getLiteral() and + ( + result.getNumber() = this.getNumber() or + result.getName() = this.getName() + ) + } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpBackRef" } + + override predicate isNullable() { this.getGroup().isNullable() } + } + + /** + * A named character property. For example, the POSIX bracket expression + * `[[:digit:]]`. + */ + additional class RegExpNamedCharacterProperty extends RegExpTerm, TRegExpNamedCharacterProperty { + RegExpNamedCharacterProperty() { this = TRegExpNamedCharacterProperty(re, start, end) } + + override RegExpTerm getChild(int i) { none() } + + override string getAPrimaryQlClass() { result = "RegExpNamedCharacterProperty" } + + /** + * Gets the property name. For example, in `\p{Space}`, the result is + * `"Space"`. + */ + string getName() { result = re.getCharacterPropertyName(start, end) } + + /** + * Holds if the property is inverted. For example, it holds for `\p{^Digit}`, + * which matches non-digits. + */ + predicate isInverted() { re.namedCharacterPropertyIsInverted(start, end) } + } + + class Top = RegExpParent; + + /** + * Holds if `term` is an escape class representing e.g. `\d`. + * `clazz` is which character class it represents, e.g. "d" for `\d`. + */ + predicate isEscapeClass(RegExpTerm term, string clazz) { + exists(RegExpCharacterClassEscape escape | term = escape | escape.getValue() = clazz) + or + // TODO: expand to cover more properties + exists(RegExpNamedCharacterProperty escape | term = escape | + escape.getName().toLowerCase() = "digit" and + if escape.isInverted() then clazz = "D" else clazz = "d" + or + escape.getName().toLowerCase() = "space" and + if escape.isInverted() then clazz = "S" else clazz = "s" + or + escape.getName().toLowerCase() = "word" and + if escape.isInverted() then clazz = "W" else clazz = "w" + ) + } + + /** + * Holds if the regular expression should not be considered. + */ + predicate isExcluded(RegExpParent parent) { + parent.(RegExpTerm).getRegExp().(Ast::RegExpLiteral).hasFreeSpacingFlag() // exclude free-spacing mode regexes + } + + /** + * Holds if `term` is a possessive quantifier. + * Not currently implemented, but is used by the shared library. + */ + predicate isPossessive(RegExpQuantifier term) { none() } + + /** + * Holds if the regex that `term` is part of is used in a way that ignores any leading prefix of the input it's matched against. + * Not yet implemented for Ruby. + */ + predicate matchesAnyPrefix(RegExpTerm term) { any() } + + /** + * Holds if the regex that `term` is part of is used in a way that ignores any trailing suffix of the input it's matched against. + * Not yet implemented for Ruby. + */ + predicate matchesAnySuffix(RegExpTerm term) { any() } + + /** + * Holds if `root` has the `i` flag for case-insensitive matching. + */ + predicate isIgnoreCase(RegExpTerm root) { + root.isRootTerm() and + root.getLiteral().isIgnoreCase() + } + + /** + * Holds if `root` has the `s` flag for multi-line matching. + */ + predicate isDotAll(RegExpTerm root) { + root.isRootTerm() and + root.getLiteral().isDotAll() + } +} diff --git a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll new file mode 100644 index 00000000000..9160bf60506 --- /dev/null +++ b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll @@ -0,0 +1,1037 @@ +/** + * Library for parsing for Ruby regular expressions. + * + * N.B. does not yet handle stripping whitespace and comments in regexes with + * the `x` (free-spacing) flag. + */ + +private import codeql.ruby.AST as Ast +private import codeql.Locations + +/** + * A `StringlikeLiteral` containing a regular expression term, that is, either + * a regular expression literal, or a string literal used in a context where + * it is parsed as regular expression. + */ +abstract class RegExp extends Ast::StringlikeLiteral { + /** + * Holds if this `RegExp` has the `s` flag for multi-line matching. + */ + predicate isDotAll() { none() } + + /** + * Holds if this `RegExp` has the `i` flag for case-insensitive matching. + */ + predicate isIgnoreCase() { none() } + + /** + * Gets the flags for this `RegExp`, or the empty string if it has no flags. + */ + string getFlags() { result = "" } + + /** + * Helper predicate for `charSetStart(int start, int end)`. + * + * In order to identify left brackets ('[') which actually start a character class, + * we perform a left to right scan of the string. + * + * To avoid negative recursion we return a boolean. See `escaping`, + * the helper for `escapingChar`, for a clean use of this pattern. + * + * result is true for those start chars that actually mark a start of a char set. + */ + boolean charSetStart(int pos) { + exists(int index | + // is opening bracket + this.charSetDelimiter(index, pos) = true and + ( + // if this is the first bracket, `pos` starts a char set + index = 1 and result = true + or + // if the previous char set delimiter was not a closing bracket, `pos` does + // not start a char set. This is needed to handle cases such as `[[]` (a + // char set that matches the `[` char) + index > 1 and + not this.charSetDelimiter(index - 1, _) = false and + result = false + or + // special handling of cases such as `[][]` (the character-set of the characters `]` and `[`). + exists(int prevClosingBracketPos | + // previous bracket is a closing bracket + this.charSetDelimiter(index - 1, prevClosingBracketPos) = false and + if + // check if the character that comes before the previous closing bracket + // is an opening bracket (taking `^` into account) + // check if the character that comes before the previous closing bracket + // is an opening bracket (taking `^` into account) + exists(int posBeforePrevClosingBracket | + if this.getChar(prevClosingBracketPos - 1) = "^" + then posBeforePrevClosingBracket = prevClosingBracketPos - 2 + else posBeforePrevClosingBracket = prevClosingBracketPos - 1 + | + this.charSetDelimiter(index - 2, posBeforePrevClosingBracket) = true + ) + then + // brackets without anything in between is not valid character ranges, so + // the first closing bracket in `[]]` and `[^]]` does not count, + // + // and we should _not_ mark the second opening bracket in `[][]` and `[^][]` + // as starting a new char set. ^ ^ + exists(int posBeforePrevClosingBracket | + this.charSetDelimiter(index - 2, posBeforePrevClosingBracket) = true + | + result = this.charSetStart(posBeforePrevClosingBracket).booleanNot() + ) + else + // if not, `pos` does in fact mark a real start of a character range + result = true + ) + ) + ) + } + + /** + * Helper predicate for chars that could be character-set delimiters. + * Holds if the (non-escaped) char at `pos` in the string, is the (one-based) `index` occurrence of a bracket (`[` or `]`) in the string. + * Result if `true` is the char is `[`, and `false` if the char is `]`. + */ + boolean charSetDelimiter(int index, int pos) { + pos = + rank[index](int p | + (this.nonEscapedCharAt(p) = "[" or this.nonEscapedCharAt(p) = "]") and + // Brackets that art part of POSIX expressions should not count as + // char-set delimiters. + not exists(int x, int y | + this.posixStyleNamedCharacterProperty(x, y, _) and pos >= x and pos < y + ) + ) and + ( + this.nonEscapedCharAt(pos) = "[" and result = true + or + this.nonEscapedCharAt(pos) = "]" and result = false + ) + } + + /** Holds if a character set starts between `start` and `end`. */ + predicate charSetStart(int start, int end) { + this.charSetStart(start) = true and + ( + this.getChar(start + 1) = "^" and end = start + 2 + or + not this.getChar(start + 1) = "^" and end = start + 1 + ) + } + + /** Whether there is a character class, between start (inclusive) and end (exclusive) */ + predicate charSet(int start, int end) { + exists(int innerStart, int innerEnd | + this.charSetStart(start, innerStart) and + not this.charSetStart(_, start) + | + end = innerEnd + 1 and + innerEnd = + min(int e | + e > innerStart and + this.nonEscapedCharAt(e) = "]" and + not exists(int x, int y | + this.posixStyleNamedCharacterProperty(x, y, _) and e >= x and e < y + ) + | + e + ) + ) + } + + /** + * Holds if the character set starting at `charsetStart` contains either + * a character or a `-` found between `start` and `end`. + */ + private predicate charSetToken(int charsetStart, int index, int tokenStart, int tokenEnd) { + tokenStart = + rank[index](int start, int end | this.charSetToken(charsetStart, start, end) | start) and + this.charSetToken(charsetStart, tokenStart, tokenEnd) + } + + /** + * Holds if the character set starting at `charsetStart` contains either + * a character or a `-` found between `start` and `end`. + */ + private predicate charSetToken(int charsetStart, int start, int end) { + this.charSetStart(charsetStart, start) and + ( + this.escapedCharacter(start, end) + or + this.namedCharacterProperty(start, end, _) + or + exists(this.nonEscapedCharAt(start)) and end = start + 1 + ) + or + this.charSetToken(charsetStart, _, start) and + ( + this.escapedCharacter(start, end) + or + this.namedCharacterProperty(start, end, _) + or + exists(this.nonEscapedCharAt(start)) and + end = start + 1 and + not this.getChar(start) = "]" + ) + } + + /** + * Holds if the character set starting at `charsetStart` contains either + * a character or a range found between `start` and `end`. + */ + predicate charSetChild(int charsetStart, int start, int end) { + this.charSetToken(charsetStart, start, end) and + not exists(int rangeStart, int rangeEnd | + this.charRange(charsetStart, rangeStart, _, _, rangeEnd) and + rangeStart <= start and + rangeEnd >= end + ) + or + this.charRange(charsetStart, start, _, _, end) + } + + /** + * Holds if the character set starting at `charset_start` contains a character range + * with lower bound found between `start` and `lower_end` + * and upper bound found between `upper_start` and `end`. + */ + predicate charRange(int charsetStart, int start, int lowerEnd, int upperStart, int end) { + exists(int index | + this.charRangeEnd(charsetStart, index) = true and + this.charSetToken(charsetStart, index - 2, start, lowerEnd) and + this.charSetToken(charsetStart, index, upperStart, end) + ) + } + + /** + * Helper predicate for `charRange`. + * We can determine where character ranges end by a left to right sweep. + * + * To avoid negative recursion we return a boolean. See `escaping`, + * the helper for `escapingChar`, for a clean use of this pattern. + */ + private boolean charRangeEnd(int charsetStart, int index) { + this.charSetToken(charsetStart, index, _, _) and + ( + index in [1, 2] and result = false + or + index > 2 and + exists(int connectorStart | + this.charSetToken(charsetStart, index - 1, connectorStart, _) and + this.nonEscapedCharAt(connectorStart) = "-" and + result = + this.charRangeEnd(charsetStart, index - 2) + .booleanNot() + .booleanAnd(this.charRangeEnd(charsetStart, index - 1).booleanNot()) + ) + or + not exists(int connectorStart | + this.charSetToken(charsetStart, index - 1, connectorStart, _) and + this.nonEscapedCharAt(connectorStart) = "-" + ) and + result = false + ) + } + + /** Holds if the character at `pos` is a "\" that is actually escaping what comes after. */ + predicate escapingChar(int pos) { this.escaping(pos) = true } + + /** + * Helper predicate for `escapingChar`. + * In order to avoid negative recursion, we return a boolean. + * This way, we can refer to `escaping(pos - 1).booleanNot()` + * rather than to a negated version of `escaping(pos)`. + */ + private boolean escaping(int pos) { + pos = -1 and result = false + or + this.getChar(pos) = "\\" and result = this.escaping(pos - 1).booleanNot() + or + this.getChar(pos) != "\\" and result = false + } + + /** Gets the text of this regex */ + string getText() { + exists(Ast::ConstantValue c | c = this.getConstantValue() | + result = [this.getConstantValue().getString(), this.getConstantValue().getRegExp()] + ) + } + + /** Gets the `i`th character of this regex */ + string getChar(int i) { result = this.getText().charAt(i) } + + /** Gets the `i`th character of this regex, unless it is part of a character escape sequence. */ + string nonEscapedCharAt(int i) { + result = this.getText().charAt(i) and + not exists(int x, int y | this.escapedCharacter(x, y) and i in [x .. y - 1]) + } + + private predicate isOptionDivider(int i) { this.nonEscapedCharAt(i) = "|" } + + private predicate isGroupEnd(int i) { this.nonEscapedCharAt(i) = ")" and not this.inCharSet(i) } + + private predicate isGroupStart(int i) { this.nonEscapedCharAt(i) = "(" and not this.inCharSet(i) } + + /** + * Holds if the `i`th character could not be parsed. + */ + predicate failedToParse(int i) { + exists(this.getChar(i)) and + not exists(int start, int end | + this.topLevel(start, end) and + start <= i and + end > i + ) + } + + /** Matches named character properties such as `\p{Word}` and `[[:digit:]]` */ + predicate namedCharacterProperty(int start, int end, string name) { + this.pStyleNamedCharacterProperty(start, end, name) or + this.posixStyleNamedCharacterProperty(start, end, name) + } + + /** Gets the name of the character property in start,end */ + string getCharacterPropertyName(int start, int end) { + this.namedCharacterProperty(start, end, result) + } + + /** Matches a POSIX bracket expression such as `[:alnum:]` within a character class. */ + private predicate posixStyleNamedCharacterProperty(int start, int end, string name) { + this.getChar(start) = "[" and + this.getChar(start + 1) = ":" and + end = + min(int e | + e > start and + this.getChar(e - 2) = ":" and + this.getChar(e - 1) = "]" + | + e + ) and + exists(int nameStart | + this.getChar(start + 2) = "^" and nameStart = start + 3 + or + not this.getChar(start + 2) = "^" and nameStart = start + 2 + | + name = this.getText().substring(nameStart, end - 2) + ) + } + + /** + * Matches named character properties. For example: + * - `\p{Space}` + * - `\P{Digit}` upper-case P means inverted + * - `\p{^Word}` caret also means inverted + * + * These can occur both inside and outside of character classes. + */ + private predicate pStyleNamedCharacterProperty(int start, int end, string name) { + this.escapingChar(start) and + this.getChar(start + 1) in ["p", "P"] and + this.getChar(start + 2) = "{" and + this.getChar(end - 1) = "}" and + end > start and + not exists(int i | start + 2 < i and i < end - 1 | this.getChar(i) = "}") and + exists(int nameStart | + this.getChar(start + 3) = "^" and nameStart = start + 4 + or + not this.getChar(start + 3) = "^" and nameStart = start + 3 + | + name = this.getText().substring(nameStart, end - 1) + ) + } + + /** + * Holds if the named character property is inverted. Examples for which it holds: + * - `\P{Digit}` upper-case P means inverted + * - `\p{^Word}` caret also means inverted + * - `[[:^digit:]]` + * + * Examples for which it doesn't hold: + * - `\p{Word}` + * - `\P{^Space}` - upper-case P and caret cancel each other out + * - `[[:alnum:]]` + */ + predicate namedCharacterPropertyIsInverted(int start, int end) { + this.pStyleNamedCharacterProperty(start, end, _) and + exists(boolean upperP, boolean caret | + (if this.getChar(start + 1) = "P" then upperP = true else upperP = false) and + (if this.getChar(start + 3) = "^" then caret = true else caret = false) + | + upperP.booleanXor(caret) = true + ) + or + this.posixStyleNamedCharacterProperty(start, end, _) and + this.getChar(start + 3) = "^" + } + + /** + * Holds if an escaped character is found between `start` and `end`. + * Escaped characters include hex values, octal values and named escapes, + * but excludes backreferences. + */ + predicate escapedCharacter(int start, int end) { + this.escapingChar(start) and + not this.numberedBackreference(start, _, _) and + not this.namedBackreference(start, _, _) and + not this.pStyleNamedCharacterProperty(start, _, _) and + ( + // hex char \xhh + this.getChar(start + 1) = "x" and end = start + 4 + or + // wide hex char \uhhhh + this.getChar(start + 1) = "u" and end = start + 6 + or + // escape not handled above; update when adding a new case + not this.getChar(start + 1) in ["x", "u"] and + not exists(this.getChar(start + 1).toInt()) and + end = start + 2 + ) + } + + /** + * Holds if the character at `index` is inside a character set. + */ + predicate inCharSet(int index) { + exists(int x, int y | this.charSet(x, y) and index in [x + 1 .. y - 2]) + } + + /** + * Holds if the character at `index` is inside a posix bracket. + */ + predicate inPosixBracket(int index) { + exists(int x, int y | + this.posixStyleNamedCharacterProperty(x, y, _) and index in [x + 1 .. y - 2] + ) + } + + /** + * 'simple' characters are any that don't alter the parsing of the regex. + */ + private predicate simpleCharacter(int start, int end) { + end = start + 1 and + not this.charSet(start, _) and + not this.charSet(_, start + 1) and + not exists(int x, int y | + this.posixStyleNamedCharacterProperty(x, y, _) and + start >= x and + end <= y + ) and + exists(string c | c = this.getChar(start) | + exists(int x, int y, int z | + this.charSet(x, z) and + this.charSetStart(x, y) + | + start = y + or + start = z - 2 + or + start > y and start < z - 2 and not this.charRange(_, _, start, end, _) + ) + or + not this.inCharSet(start) and + not c = "(" and + not c = "[" and + not c = ")" and + not c = "|" and + not this.qualifier(start, _, _, _) + ) + } + + /** + * Holds if a simple or escaped character is found between `start` and `end`. + */ + predicate character(int start, int end) { + ( + this.simpleCharacter(start, end) and + not exists(int x, int y | this.escapedCharacter(x, y) and x <= start and y >= end) + or + this.escapedCharacter(start, end) + ) and + not exists(int x, int y | this.groupStart(x, y) and x <= start and y >= end) and + not exists(int x, int y | this.backreference(x, y) and x <= start and y >= end) and + not exists(int x, int y | + this.pStyleNamedCharacterProperty(x, y, _) and x <= start and y >= end + ) and + not exists(int x, int y | this.multiples(x, y, _, _) and x <= start and y >= end) + } + + /** + * Holds if a normal character is found between `start` and `end`. + */ + predicate normalCharacter(int start, int end) { + end = start + 1 and + this.character(start, end) and + not this.specialCharacter(start, end, _) + } + + /** + * Holds if a special character is found between `start` and `end`. + */ + predicate specialCharacter(int start, int end, string char) { + this.character(start, end) and + not this.inCharSet(start) and + ( + end = start + 1 and + char = this.getChar(start) and + (char = "$" or char = "^" or char = ".") + or + end = start + 2 and + this.escapingChar(start) and + char = this.getText().substring(start, end) and + char = ["\\A", "\\Z", "\\z", "\\G", "\\b", "\\B"] + ) + } + + /** + * Holds if the range [start:end) consists of only 'normal' characters. + */ + predicate normalCharacterSequence(int start, int end) { + // a normal character inside a character set is interpreted on its own + this.normalCharacter(start, end) and + this.inCharSet(start) + or + // a maximal run of normal characters is considered as one constant + exists(int s, int e | + e = max(int i | this.normalCharacterRun(s, i)) and + not this.inCharSet(s) + | + // 'abc' can be considered one constant, but + // 'abc+' has to be broken up into 'ab' and 'c+', + // as the qualifier only applies to 'c'. + if this.qualifier(e, _, _, _) + then + end = e and start = e - 1 + or + end = e - 1 and start = s and start < end + else ( + end = e and + start = s + ) + ) + } + + private predicate normalCharacterRun(int start, int end) { + ( + this.normalCharacterRun(start, end - 1) + or + start = end - 1 and not this.normalCharacter(start - 1, start) + ) and + this.normalCharacter(end - 1, end) + } + + private predicate characterItem(int start, int end) { + this.normalCharacterSequence(start, end) or + this.escapedCharacter(start, end) or + this.specialCharacter(start, end, _) + } + + /** Whether the text in the range `start,end` is a group */ + predicate group(int start, int end) { + this.groupContents(start, end, _, _) + or + this.emptyGroup(start, end) + } + + /** Gets the number of the group in start,end */ + int getGroupNumber(int start, int end) { + this.group(start, end) and + not this.nonCapturingGroupStart(start, _) and + result = + count(int i | this.group(i, _) and i < start and not this.nonCapturingGroupStart(i, _)) + 1 + } + + /** Gets the name, if it has one, of the group in start,end */ + string getGroupName(int start, int end) { + this.group(start, end) and + exists(int nameEnd | + this.namedGroupStart(start, nameEnd) and + result = this.getText().substring(start + 3, nameEnd - 1) + ) + } + + /** Whether the text in the range start, end is a group and can match the empty string. */ + predicate zeroWidthMatch(int start, int end) { + this.emptyGroup(start, end) + or + this.negativeAssertionGroup(start, end) + or + this.positiveLookaheadAssertionGroup(start, end) + or + this.positiveLookbehindAssertionGroup(start, end) + } + + /** Holds if an empty group is found between `start` and `end`. */ + predicate emptyGroup(int start, int end) { + exists(int endm1 | end = endm1 + 1 | + this.groupStart(start, endm1) and + this.isGroupEnd(endm1) + ) + } + + private predicate emptyMatchAtStartGroup(int start, int end) { + this.emptyGroup(start, end) + or + this.negativeAssertionGroup(start, end) + or + this.positiveLookaheadAssertionGroup(start, end) + } + + private predicate emptyMatchAtEndGroup(int start, int end) { + this.emptyGroup(start, end) + or + this.negativeAssertionGroup(start, end) + or + this.positiveLookbehindAssertionGroup(start, end) + } + + private predicate negativeAssertionGroup(int start, int end) { + exists(int inStart | + this.negativeLookaheadAssertionStart(start, inStart) + or + this.negativeLookbehindAssertionStart(start, inStart) + | + this.groupContents(start, end, inStart, _) + ) + } + + /** Holds if a negative lookahead is found between `start` and `end` */ + predicate negativeLookaheadAssertionGroup(int start, int end) { + exists(int inStart | this.negativeLookaheadAssertionStart(start, inStart) | + this.groupContents(start, end, inStart, _) + ) + } + + /** Holds if a negative lookbehind is found between `start` and `end` */ + predicate negativeLookbehindAssertionGroup(int start, int end) { + exists(int inStart | this.negativeLookbehindAssertionStart(start, inStart) | + this.groupContents(start, end, inStart, _) + ) + } + + /** Holds if a positive lookahead is found between `start` and `end` */ + predicate positiveLookaheadAssertionGroup(int start, int end) { + exists(int inStart | this.lookaheadAssertionStart(start, inStart) | + this.groupContents(start, end, inStart, _) + ) + } + + /** Holds if a positive lookbehind is found between `start` and `end` */ + predicate positiveLookbehindAssertionGroup(int start, int end) { + exists(int inStart | this.lookbehindAssertionStart(start, inStart) | + this.groupContents(start, end, inStart, _) + ) + } + + private predicate groupStart(int start, int end) { + this.nonCapturingGroupStart(start, end) + or + this.namedGroupStart(start, end) + or + this.lookaheadAssertionStart(start, end) + or + this.negativeLookaheadAssertionStart(start, end) + or + this.lookbehindAssertionStart(start, end) + or + this.negativeLookbehindAssertionStart(start, end) + or + this.commentGroupStart(start, end) + or + this.simpleGroupStart(start, end) + } + + /** Matches the start of a non-capturing group, e.g. `(?:` */ + private predicate nonCapturingGroupStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = [":", "=", "<", "!", "#"] and + end = start + 3 + } + + /** Matches the start of a simple group, e.g. `(a+)`. */ + private predicate simpleGroupStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) != "?" and + end = start + 1 + } + + /** + * Matches the start of a named group, such as: + * - `(?\w+)` + * - `(?'name'\w+)` + */ + private predicate namedGroupStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + ( + this.getChar(start + 2) = "<" and + not this.getChar(start + 3) = "=" and // (?<=foo) is a positive lookbehind assertion + not this.getChar(start + 3) = "!" and // (? start + 3 and this.getChar(i) = ">") and + end = nameEnd + 1 + ) + or + this.getChar(start + 2) = "'" and + exists(int nameEnd | + nameEnd = min(int i | i > start + 2 and this.getChar(i) = "'") and end = nameEnd + 1 + ) + ) + } + + /** Matches the start of a positive lookahead assertion, i.e. `(?=`. */ + private predicate lookaheadAssertionStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "=" and + end = start + 3 + } + + /** Matches the start of a negative lookahead assertion, i.e. `(?!`. */ + private predicate negativeLookaheadAssertionStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "!" and + end = start + 3 + } + + /** Matches the start of a positive lookbehind assertion, i.e. `(?<=`. */ + private predicate lookbehindAssertionStart(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "<" and + this.getChar(start + 3) = "=" and + end = start + 4 + } + + /** Matches the start of a negative lookbehind assertion, i.e. `(?`. */ + predicate namedBackreference(int start, int end, string name) { + this.escapingChar(start) and + this.getChar(start + 1) = "k" and + this.getChar(start + 2) = "<" and + exists(int nameEnd | nameEnd = min(int i | i > start + 3 and this.getChar(i) = ">") | + end = nameEnd + 1 and + name = this.getText().substring(start + 3, nameEnd) + ) + } + + /** Matches a numbered backreference, e.g. `\1`. */ + predicate numberedBackreference(int start, int end, int value) { + this.escapingChar(start) and + not this.getChar(start + 1) = "0" and + exists(string text, string svalue, int len | + end = start + len and + text = this.getText() and + len in [2 .. 3] + | + svalue = text.substring(start + 1, start + len) and + value = svalue.toInt() and + not exists(text.substring(start + 1, start + len + 1).toInt()) and + value > 0 + ) + } + + /** Whether the text in the range `start,end` is a back reference */ + predicate backreference(int start, int end) { + this.numberedBackreference(start, end, _) + or + this.namedBackreference(start, end, _) + } + + /** Gets the number of the back reference in start,end */ + int getBackRefNumber(int start, int end) { this.numberedBackreference(start, end, result) } + + /** Gets the name, if it has one, of the back reference in start,end */ + string getBackRefName(int start, int end) { this.namedBackreference(start, end, result) } + + private predicate baseItem(int start, int end) { + this.characterItem(start, end) and + not exists(int x, int y | this.charSet(x, y) and x <= start and y >= end) + or + this.group(start, end) + or + this.charSet(start, end) + or + this.backreference(start, end) + or + this.pStyleNamedCharacterProperty(start, end, _) + } + + private predicate qualifier(int start, int end, boolean maybeEmpty, boolean mayRepeatForever) { + this.shortQualifier(start, end, maybeEmpty, mayRepeatForever) and + not this.getChar(end) = "?" + or + exists(int shortEnd | this.shortQualifier(start, shortEnd, maybeEmpty, mayRepeatForever) | + if this.getChar(shortEnd) = "?" then end = shortEnd + 1 else end = shortEnd + ) + } + + private predicate shortQualifier(int start, int end, boolean maybeEmpty, boolean mayRepeatForever) { + ( + this.getChar(start) = "+" and maybeEmpty = false and mayRepeatForever = true + or + this.getChar(start) = "*" and maybeEmpty = true and mayRepeatForever = true + or + this.getChar(start) = "?" and maybeEmpty = true and mayRepeatForever = false + ) and + end = start + 1 + or + exists(string lower, string upper | + this.multiples(start, end, lower, upper) and + (if lower = "" or lower.toInt() = 0 then maybeEmpty = true else maybeEmpty = false) and + if upper = "" then mayRepeatForever = true else mayRepeatForever = false + ) + } + + /** + * Holds if a repetition quantifier is found between `start` and `end`, + * with the given lower and upper bounds. If a bound is omitted, the corresponding + * string is empty. + */ + predicate multiples(int start, int end, string lower, string upper) { + exists(string text, string match, string inner | + text = this.getText() and + end = start + match.length() and + inner = match.substring(1, match.length() - 1) + | + match = text.regexpFind("\\{[0-9]+\\}", _, start) and + lower = inner and + upper = lower + or + match = text.regexpFind("\\{[0-9]*,[0-9]*\\}", _, start) and + exists(int commaIndex | + commaIndex = inner.indexOf(",") and + lower = inner.prefix(commaIndex) and + upper = inner.suffix(commaIndex + 1) + ) + ) + } + + /** + * Whether the text in the range start,end is a qualified item, where item is a character, + * a character set or a group. + */ + predicate qualifiedItem(int start, int end, boolean maybeEmpty, boolean mayRepeatForever) { + this.qualifiedPart(start, _, end, maybeEmpty, mayRepeatForever) + } + + /** + * Holds if a qualified part is found between `start` and `part_end` and the qualifier is + * found between `part_end` and `end`. + * + * `maybe_empty` is true if the part is optional. + * `may_repeat_forever` is true if the part may be repeated unboundedly. + */ + predicate qualifiedPart( + int start, int partEnd, int end, boolean maybeEmpty, boolean mayRepeatForever + ) { + this.baseItem(start, partEnd) and + this.qualifier(partEnd, end, maybeEmpty, mayRepeatForever) + } + + /** Holds if the range `start`, `end` contains a character, a quantifier, a character set or a group. */ + predicate item(int start, int end) { + this.qualifiedItem(start, end, _, _) + or + this.baseItem(start, end) and not this.qualifier(end, _, _, _) + } + + private predicate subsequence(int start, int end) { + ( + start = 0 or + this.groupStart(_, start) or + this.isOptionDivider(start - 1) + ) and + this.item(start, end) + or + exists(int mid | + this.subsequence(start, mid) and + this.item(mid, end) + ) + } + + /** + * Whether the text in the range start,end is a sequence of 1 or more items, where an item is a character, + * a character set or a group. + */ + predicate sequence(int start, int end) { + this.sequenceOrQualified(start, end) and + not this.qualifiedItem(start, end, _, _) + } + + private predicate sequenceOrQualified(int start, int end) { + this.subsequence(start, end) and + not this.itemStart(end) + } + + private predicate itemStart(int start) { + this.characterItem(start, _) or + this.isGroupStart(start) or + this.charSet(start, _) or + this.backreference(start, _) or + this.namedCharacterProperty(start, _, _) + } + + private predicate itemEnd(int end) { + this.characterItem(_, end) + or + exists(int endm1 | this.isGroupEnd(endm1) and end = endm1 + 1) + or + this.charSet(_, end) + or + this.qualifier(_, end, _, _) + } + + private predicate topLevel(int start, int end) { + this.subalternation(start, end, _) and + not this.isOptionDivider(end) + } + + private predicate subalternation(int start, int end, int itemStart) { + this.sequenceOrQualified(start, end) and + not this.isOptionDivider(start - 1) and + itemStart = start + or + start = end and + not this.itemEnd(start) and + this.isOptionDivider(end) and + itemStart = start + or + exists(int mid | + this.subalternation(start, mid, _) and + this.isOptionDivider(mid) and + itemStart = mid + 1 + | + this.sequenceOrQualified(itemStart, end) + or + not this.itemStart(end) and end = itemStart + ) + } + + /** + * Whether the text in the range start,end is an alternation + */ + predicate alternation(int start, int end) { + not this.inCharSet(start) and + this.topLevel(start, end) and + exists(int less | this.subalternation(start, less, _) and less < end) + } + + /** + * Whether the text in the range start,end is an alternation and the text in partStart, partEnd is one of the + * options in that alternation. + */ + predicate alternationOption(int start, int end, int partStart, int partEnd) { + this.alternation(start, end) and + this.subalternation(start, partEnd, partStart) + } + + /** A part of the regex that may match the start of the string. */ + private predicate firstPart(int start, int end) { + start = 0 and end = this.getText().length() + or + exists(int x | this.firstPart(x, end) | + this.emptyMatchAtStartGroup(x, start) + or + this.qualifiedItem(x, start, true, _) + or + // ^ and \A match the start of the string + this.specialCharacter(x, start, ["^", "\\A"]) + ) + or + exists(int y | this.firstPart(start, y) | + this.item(start, end) + or + this.qualifiedPart(start, end, y, _, _) + ) + or + exists(int x, int y | this.firstPart(x, y) | + this.groupContents(x, y, start, end) + or + this.alternationOption(x, y, start, end) + ) + } + + /** A part of the regex that may match the end of the string. */ + private predicate lastPart(int start, int end) { + start = 0 and end = this.getText().length() + or + exists(int y | this.lastPart(start, y) | + this.emptyMatchAtEndGroup(end, y) + or + this.qualifiedItem(end, y, true, _) + or + // $, \Z, and \z match the end of the string. + this.specialCharacter(end, y, ["$", "\\Z", "\\z"]) + ) + or + this.lastPart(_, end) and + this.item(start, end) + or + exists(int y | this.lastPart(start, y) | this.qualifiedPart(start, end, y, _, _)) + or + exists(int x, int y | this.lastPart(x, y) | + this.groupContents(x, y, start, end) + or + this.alternationOption(x, y, start, end) + ) + } + + /** + * Whether the item at [start, end) is one of the first items + * to be matched. + */ + predicate firstItem(int start, int end) { + ( + this.characterItem(start, end) + or + this.qualifiedItem(start, end, _, _) + or + this.charSet(start, end) + ) and + this.firstPart(start, end) + } + + /** + * Whether the item at [start, end) is one of the last items + * to be matched. + */ + predicate lastItem(int start, int end) { + ( + this.characterItem(start, end) + or + this.qualifiedItem(start, end, _, _) + or + this.charSet(start, end) + ) and + this.lastPart(start, end) + } +} From 5f85b7419f9e444bf0ca9b2082b8abe896318f93 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 7 Jun 2023 11:43:13 +0100 Subject: [PATCH 107/364] Swift: Trivial changes to get it compiling. --- .../lib/codeql/swift/regex/RegexTreeView.qll | 33 ++++++++++--------- .../swift/regex/internal/ParseRegex.qll | 17 +++++----- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll index 51df1700881..bc401cc1698 100644 --- a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll +++ b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll @@ -1,20 +1,16 @@ -/** Provides a class hierarchy corresponding to a parse tree of regular expressions. */ +/** + * Provides a class hierarchy corresponding to a parse tree of regular expressions. + */ -private import internal.ParseRegExp +import swift +private import internal.ParseRegex private import codeql.util.Numbers -private import codeql.ruby.ast.Literal as Ast -private import codeql.Locations private import codeql.regex.nfa.NfaUtils as NfaUtils private import codeql.regex.RegexTreeView // exporting as RegexTreeView, and in the top-level scope. import Impl as RegexTreeView import Impl -/** Gets the parse tree resulting from parsing `re`, if such has been constructed. */ -RegExpTerm getParsedRegExp(Ast::RegExpLiteral re) { - result.getRegExp() = re and result.isRootTerm() -} - /** * An element containing a regular expression term, that is, either * a string literal (parsed as a regular expression) @@ -211,25 +207,30 @@ private module Impl implements RegexTreeViewSig { */ Location getLocation() { result = re.getLocation() } - pragma[noinline] + /*pragma[noinline] private predicate componentHasLocationInfo( int i, string filepath, int startline, int startcolumn, int endline, int endcolumn ) { re.getComponent(i) .getLocation() .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } + }*/ /** Holds if this term is found at the specified location offsets. */ predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - exists(int re_start | + /*exists(int re_start | this.componentHasLocationInfo(0, filepath, startline, re_start, _, _) and this.componentHasLocationInfo(re.getNumberOfComponents() - 1, filepath, _, _, endline, _) and startcolumn = re_start + start and endcolumn = re_start + end - 1 - ) + )*/ + filepath = re.getFile().getAbsolutePath() and + startline = re.getLocation().getStartLine() and + startcolumn = re.getLocation().getStartColumn() and + endline = re.getLocation().getEndLine() and + endcolumn = re.getLocation().getEndColumn() } /** Gets the file in which this term is found. */ @@ -1196,7 +1197,7 @@ private module Impl implements RegexTreeViewSig { * Holds if the regular expression should not be considered. */ predicate isExcluded(RegExpParent parent) { - parent.(RegExpTerm).getRegExp().(Ast::RegExpLiteral).hasFreeSpacingFlag() // exclude free-spacing mode regexes + none()//parent.(RegExpTerm).getRegExp().(Ast::RegExpLiteral).hasFreeSpacingFlag() // exclude free-spacing mode regexes } /** @@ -1207,13 +1208,13 @@ private module Impl implements RegexTreeViewSig { /** * Holds if the regex that `term` is part of is used in a way that ignores any leading prefix of the input it's matched against. - * Not yet implemented for Ruby. + * Not yet implemented for Swift. */ predicate matchesAnyPrefix(RegExpTerm term) { any() } /** * Holds if the regex that `term` is part of is used in a way that ignores any trailing suffix of the input it's matched against. - * Not yet implemented for Ruby. + * Not yet implemented for Swift. */ predicate matchesAnySuffix(RegExpTerm term) { any() } diff --git a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll index 9160bf60506..36450bcdfb9 100644 --- a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll +++ b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll @@ -1,19 +1,18 @@ /** - * Library for parsing for Ruby regular expressions. + * Library for parsing Swift regular expressions. * * N.B. does not yet handle stripping whitespace and comments in regexes with * the `x` (free-spacing) flag. */ -private import codeql.ruby.AST as Ast -private import codeql.Locations +import swift /** - * A `StringlikeLiteral` containing a regular expression term, that is, either + * A `Expr` containing a regular expression term, that is, either * a regular expression literal, or a string literal used in a context where * it is parsed as regular expression. */ -abstract class RegExp extends Ast::StringlikeLiteral { +abstract class RegExp extends Expr { /** * Holds if this `RegExp` has the `s` flag for multi-line matching. */ @@ -253,11 +252,11 @@ abstract class RegExp extends Ast::StringlikeLiteral { this.getChar(pos) != "\\" and result = false } - /** Gets the text of this regex */ + /** + * Gets the text of this regex. + */ string getText() { - exists(Ast::ConstantValue c | c = this.getConstantValue() | - result = [this.getConstantValue().getString(), this.getConstantValue().getRegExp()] - ) + result = this.(StringLiteralExpr).getValue() } /** Gets the `i`th character of this regex */ From d4c3e9eb16e57acef509164da1d5f8a38b3155f7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 7 Jun 2023 15:41:51 +0100 Subject: [PATCH 108/364] Swift: Include the shared regex pack in Swift. --- swift/ql/lib/qlpack.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index f45d347bad3..d247e4da4f5 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -6,6 +6,7 @@ dbscheme: swift.dbscheme upgrades: upgrades library: true dependencies: + codeql/regex: ${workspace} codeql/ssa: ${workspace} codeql/tutorial: ${workspace} codeql/util: ${workspace} From 1e290b48bb8f00245f4603274eb6f22a5baba5cf Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 7 Jun 2023 12:15:46 +0100 Subject: [PATCH 109/364] Swift: Add REDOS analysis to the library test. --- swift/ql/test/library-tests/regex/regex.ql | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/swift/ql/test/library-tests/regex/regex.ql b/swift/ql/test/library-tests/regex/regex.ql index 902355dd78a..ad251a7b75d 100644 --- a/swift/ql/test/library-tests/regex/regex.ql +++ b/swift/ql/test/library-tests/regex/regex.ql @@ -1,12 +1,14 @@ import swift import codeql.swift.regex.Regex +private import codeql.swift.regex.RegexTreeView::RegexTreeView as TreeView +import codeql.regex.nfa.ExponentialBackTracking::Make import TestUtilities.InlineExpectationsTest bindingset[s] string quote(string s) { if s.matches("% %") then result = "\"" + s + "\"" else result = s } module RegexTest implements TestSig { - string getARelevantTag() { result = ["regex", "input"] } + string getARelevantTag() { result = ["regex", "input", "redos-vulnerable"] } predicate hasActualResult(Location location, string element, string tag, string value) { exists(RegexEval eval, Expr regex | @@ -24,6 +26,14 @@ module RegexTest implements TestSig { tag = "input" and value = quote(input.toString()) ) + or + exists(TreeView::RegExpTerm t, string pump, State s, string prefixMsg | + hasReDoSResult(t, pump, s, prefixMsg) and + location = t.getLocation() and + element = t.toString() and + tag = "redos-vulnerable" and + value = "" + ) } } From 7e9d73b6b2dd50de1d60ff30e1b6ca3bbe59d47e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 7 Jun 2023 17:25:44 +0100 Subject: [PATCH 110/364] Swift: Add regex sources to the library. --- swift/ql/lib/codeql/swift/regex/Regex.qll | 63 ++++++++++++++++++- .../library-tests/regex/redos_variants.swift | 6 +- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/Regex.qll b/swift/ql/lib/codeql/swift/regex/Regex.qll index e90df6ea1cc..00f1d7cb394 100644 --- a/swift/ql/lib/codeql/swift/regex/Regex.qll +++ b/swift/ql/lib/codeql/swift/regex/Regex.qll @@ -1,8 +1,69 @@ /** - * Provides classes and predicates for reasoning about use of regular expressions. + * Provides classes and predicates for reasoning about regular expressions. */ import swift +import codeql.swift.dataflow.DataFlow + +import codeql.swift.regex.RegexTreeView // re-export +private import internal.ParseRegex +//private import codeql.regex.internal.RegExpTracking as RegExpTracking + +/** + * A node whose value may flow to a position where it is interpreted + * as a part of a regular expression. + */ +abstract class RegExpPatternSource extends DataFlow::Node { + /** + * Gets a node where the pattern of this node is parsed as a part of + * a regular expression. + */ + abstract DataFlow::Node getAParse(); + + /** + * Gets the root term of the regular expression parsed from this pattern. + */ + abstract RegExpTerm getRegExpTerm(); +} + +/* * + * A node whose string value may flow to a position where it is interpreted + * as a part of a regular expression. + * +private class StringRegExpPatternSource extends RegExpPatternSource { + private DataFlow::Node parse; + + StringRegExpPatternSource() { + this = regExpSource(parse) and + // `regExpSource()` tracks both strings and regex literals, narrow it down to strings. + this.asExpr().getConstantValue().isString(_) + } + + override DataFlow::Node getAParse() { result = parse } + + override RegExpTerm getRegExpTerm() { result.getRegExp() = this.asExpr().getExpr() } +}*/ + +/** + * TODO + * "(a|b).*" + */ +private class ParsedStringRegExp extends RegExp, StringLiteralExpr { + private DataFlow::Node parse; + + ParsedStringRegExp() { + //this = regExpSource(parse).asExpr().getExpr() + parse.asExpr() = this + } + + DataFlow::Node getAParse() { result = parse } + /* + override predicate isDotAll() { none() } + + override predicate isIgnoreCase() { none() } + + override string getFlags() { none() }*/ +} /** * A call that evaluates a regular expression. For example: diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 4bd1224d89a..9e90e418a42 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -40,11 +40,11 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("a*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted _ = try Regex("(a*)b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted _ = try Regex("(a)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted - _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted MISSING: redos-vulnerable= - _ = try Regex("((a*)*b)").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted MISSING: redos-vulnerable= + _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted redos-vulnerable= + _ = try Regex("((a*)*b)").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted redos-vulnerable= _ = try Regex("(a|aa?)b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted - _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted MISSING: redos-vulnerable= + _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted redos-vulnerable= // TODO: test more variant expressions. } From 712c3cc698247e5287c3aecb059c9dd02286ffff Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 12 Jun 2023 11:59:06 +0100 Subject: [PATCH 111/364] Swift: Add the cases from the (Ruby) qhelp to the library tests. --- swift/ql/test/library-tests/regex/redos_variants.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 9e90e418a42..c7904efa8ff 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -46,5 +46,9 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("(a|aa?)b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted redos-vulnerable= + // from the qhelp: + _ = try Regex("^_(__|.)+_$").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted redos-vulnerable= + _ = try Regex("^_(__|[^_])+_$").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted + // TODO: test more variant expressions. } From 2ccbdbdf870316abf583b6c2f6a3911efb65668a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 12 Jun 2023 13:38:37 +0100 Subject: [PATCH 112/364] Swift: Identify strings that are used in regular expressions properly. --- swift/ql/lib/codeql/swift/regex/Regex.qll | 111 ++++++++---------- .../library-tests/regex/redos_variants.swift | 20 ++-- swift/ql/test/library-tests/regex/regex.ql | 8 +- swift/ql/test/library-tests/regex/regex.swift | 45 ++++--- 4 files changed, 93 insertions(+), 91 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/Regex.qll b/swift/ql/lib/codeql/swift/regex/Regex.qll index 00f1d7cb394..bad4baa2c16 100644 --- a/swift/ql/lib/codeql/swift/regex/Regex.qll +++ b/swift/ql/lib/codeql/swift/regex/Regex.qll @@ -4,65 +4,53 @@ import swift import codeql.swift.dataflow.DataFlow - import codeql.swift.regex.RegexTreeView // re-export private import internal.ParseRegex -//private import codeql.regex.internal.RegExpTracking as RegExpTracking /** - * A node whose value may flow to a position where it is interpreted - * as a part of a regular expression. + * A data flow configuration for tracking string literals that are used as + * regular expressions. */ -abstract class RegExpPatternSource extends DataFlow::Node { - /** - * Gets a node where the pattern of this node is parsed as a part of - * a regular expression. - */ - abstract DataFlow::Node getAParse(); +private module RegexUseConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { node.asExpr() instanceof StringLiteralExpr } - /** - * Gets the root term of the regular expression parsed from this pattern. - */ - abstract RegExpTerm getRegExpTerm(); + predicate isSink(DataFlow::Node node) { node.asExpr() = any(RegexEval eval).getRegexInput() } + + predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // flow through `Regex` initializer, i.e. from a string to a `Regex` object. + exists(CallExpr call | + ( + call.getStaticTarget().(Method).hasQualifiedName("Regex", ["init(_:)", "init(_:as:)"]) or + call.getStaticTarget() + .(Method) + .hasQualifiedName("NSRegularExpression", "init(pattern:options:)") + ) and + nodeFrom.asExpr() = call.getArgument(0).getExpr() and + nodeTo.asExpr() = call + ) + } } -/* * - * A node whose string value may flow to a position where it is interpreted - * as a part of a regular expression. - * -private class StringRegExpPatternSource extends RegExpPatternSource { - private DataFlow::Node parse; - - StringRegExpPatternSource() { - this = regExpSource(parse) and - // `regExpSource()` tracks both strings and regex literals, narrow it down to strings. - this.asExpr().getConstantValue().isString(_) - } - - override DataFlow::Node getAParse() { result = parse } - - override RegExpTerm getRegExpTerm() { result.getRegExp() = this.asExpr().getExpr() } -}*/ +private module RegexUseFlow = DataFlow::Global; /** - * TODO - * "(a|b).*" + * A string literal that is used as a regular expression in a regular + * expression evaluation. For example the string literal `"(a|b).*"` in: + * ``` + * Regex("(a|b).*").firstMatch(in: myString) + * ``` */ -private class ParsedStringRegExp extends RegExp, StringLiteralExpr { - private DataFlow::Node parse; +private class ParsedStringRegex extends RegExp, StringLiteralExpr { + RegexEval eval; - ParsedStringRegExp() { - //this = regExpSource(parse).asExpr().getExpr() - parse.asExpr() = this + ParsedStringRegex() { + RegexUseFlow::flow(DataFlow::exprNode(this), DataFlow::exprNode(eval.getRegexInput())) } - DataFlow::Node getAParse() { result = parse } - /* - override predicate isDotAll() { none() } - - override predicate isIgnoreCase() { none() } - - override string getFlags() { none() }*/ + /** + * Gets a call that evaluates this regular expression. + */ + RegexEval getEval() { result = eval } } /** @@ -72,18 +60,23 @@ private class ParsedStringRegExp extends RegExp, StringLiteralExpr { * ``` */ abstract class RegexEval extends CallExpr { - Expr regex; - Expr input; + Expr regexInput; + Expr stringInput; /** - * Gets the regular expression that is evaluated. + * Gets the input to this call that is the regular expression. */ - Expr getRegex() { result = regex } + Expr getRegexInput() { result = regexInput } /** - * Gets the input string the regular expression is evaluated on. + * Gets the input to this call that is the string the regular expression is evaluated on. */ - Expr getInput() { result = input } + Expr getStringInput() { result = stringInput } + + /** + * Gets a regular expression value that is evaluated here (if any can be identified). + */ + RegExp getARegex() { exists(ParsedStringRegex regex | regex.getEval() = this and result = regex) } } /** @@ -94,8 +87,8 @@ private class AlwaysRegexEval extends RegexEval { this.getStaticTarget() .(Method) .hasQualifiedName("Regex", ["firstMatch(in:)", "prefixMatch(in:)", "wholeMatch(in:)"]) and - regex = this.getQualifier() and - input = this.getArgument(0).getExpr() + regexInput = this.getQualifier() and + stringInput = this.getArgument(0).getExpr() or this.getStaticTarget() .(Method) @@ -107,8 +100,8 @@ private class AlwaysRegexEval extends RegexEval { "replaceMatches(in:options:range:withTemplate:)", "stringByReplacingMatches(in:options:range:withTemplate:)" ]) and - regex = this.getQualifier() and - input = this.getArgument(0).getExpr() + regexInput = this.getQualifier() and + stringInput = this.getArgument(0).getExpr() or this.getStaticTarget() .(Method) @@ -119,8 +112,8 @@ private class AlwaysRegexEval extends RegexEval { "split(separator:maxSplits:omittingEmptySubsequences:)", "starts(with:)", "trimmingPrefix(_:)", "wholeMatch(of:)" ]) and - regex = this.getArgument(0).getExpr() and - input = this.getQualifier() + regexInput = this.getArgument(0).getExpr() and + stringInput = this.getQualifier() or this.getStaticTarget() .(Method) @@ -131,7 +124,7 @@ private class AlwaysRegexEval extends RegexEval { "replacing(_:with:maxReplacements:)", "replacing(_:with:subrange:maxReplacements:)", "trimPrefix(_:)" ]) and - regex = this.getArgument(0).getExpr() and - input = this.getQualifier() + regexInput = this.getArgument(0).getExpr() and + stringInput = this.getQualifier() } } diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index c7904efa8ff..6d5ffb886f6 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -35,20 +35,20 @@ func myRegexpVariantsTests(myUrl: URL) throws { let tainted = String(contentsOf: myUrl) // tainted let untainted = "abcdef" - _ = try Regex(".*").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted + _ = try Regex(".*").firstMatch(in: tainted) // $ regex=.* input=tainted - _ = try Regex("a*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted - _ = try Regex("(a*)b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted - _ = try Regex("(a)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted - _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted redos-vulnerable= - _ = try Regex("((a*)*b)").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted redos-vulnerable= + _ = try Regex("a*b").firstMatch(in: tainted) // $ regex=a*b input=tainted + _ = try Regex("(a*)b").firstMatch(in: tainted) // $ regex=(a*)b input=tainted + _ = try Regex("(a)*b").firstMatch(in: tainted) // $ regex=(a)*b input=tainted + _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ regex=(a*)*b input=tainted redos-vulnerable= + _ = try Regex("((a*)*b)").firstMatch(in: tainted) // $ regex=((a*)*b) input=tainted redos-vulnerable= - _ = try Regex("(a|aa?)b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted - _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted redos-vulnerable= + _ = try Regex("(a|aa?)b").firstMatch(in: tainted) // $ regex=(a|aa?)b input=tainted + _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex=(a|aa?)*b input=tainted redos-vulnerable= // from the qhelp: - _ = try Regex("^_(__|.)+_$").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted redos-vulnerable= - _ = try Regex("^_(__|[^_])+_$").firstMatch(in: tainted) // $ regex="call to Regex.init(_:)" input=tainted + _ = try Regex("^_(__|.)+_$").firstMatch(in: tainted) // $ regex=^_(__|.)+_$ input=tainted redos-vulnerable= + _ = try Regex("^_(__|[^_])+_$").firstMatch(in: tainted) // $ regex=^_(__|[^_])+_$ input=tainted // TODO: test more variant expressions. } diff --git a/swift/ql/test/library-tests/regex/regex.ql b/swift/ql/test/library-tests/regex/regex.ql index ad251a7b75d..9c055790f0a 100644 --- a/swift/ql/test/library-tests/regex/regex.ql +++ b/swift/ql/test/library-tests/regex/regex.ql @@ -12,15 +12,15 @@ module RegexTest implements TestSig { predicate hasActualResult(Location location, string element, string tag, string value) { exists(RegexEval eval, Expr regex | - eval.getRegex() = regex and - location = regex.getLocation() and - element = regex.toString() and + eval.getARegex() = regex and + location = eval.getLocation() and + element = eval.toString() and tag = "regex" and value = quote(regex.toString()) ) or exists(RegexEval eval, Expr input | - eval.getInput() = input and + eval.getStringInput() = input and location = input.getLocation() and element = input.toString() and tag = "input" and diff --git a/swift/ql/test/library-tests/regex/regex.swift b/swift/ql/test/library-tests/regex/regex.swift index 78955fe3670..088b62a040f 100644 --- a/swift/ql/test/library-tests/regex/regex.swift +++ b/swift/ql/test/library-tests/regex/regex.swift @@ -96,42 +96,51 @@ class NSRegularExpression : NSObject { // --- tests --- -func myRegexpMethodsTests() throws { +func myRegexpMethodsTests(b: Bool) throws { let input = "abcdef" let regex = try Regex(".*") // --- Regex --- - _ = try regex.firstMatch(in: input) // $ regex=regex input=input - _ = try regex.prefixMatch(in: input) // $ regex=regex input=input - _ = try regex.wholeMatch(in: input) // $ regex=regex input=input + _ = try regex.firstMatch(in: input) // $ regex=.* input=input + _ = try regex.prefixMatch(in: input) // $ regex=.* input=input + _ = try regex.wholeMatch(in: input) // $ regex=.* input=input // --- RangeReplaceableCollection --- var inputVar = input - inputVar.replace(regex, with: "") // $ regex=regex input=&... - _ = input.replacing(regex, with: "") // $ regex=regex input=input - inputVar.trimPrefix(regex) // $ regex=regex input=&... + inputVar.replace(regex, with: "") // $ regex=.* input=&... + _ = input.replacing(regex, with: "") // $ regex=.* input=input + inputVar.trimPrefix(regex) // $ regex=.* input=&... // --- StringProtocol --- - _ = input.range(of: ".*", options: .regularExpression, range: nil, locale: nil) // $ MISSING: regex=regex input=input - _ = input.replacingOccurrences(of: ".*", with: "", options: .regularExpression) // $ MISSING: regex=regex input=input + _ = input.range(of: ".*", options: .regularExpression, range: nil, locale: nil) // $ MISSING: regex=.* input=input + _ = input.replacingOccurrences(of: ".*", with: "", options: .regularExpression) // $ MISSING: regex=.* input=input // --- NSRegularExpression --- let nsregex = try NSRegularExpression(pattern: ".*") - _ = nsregex.numberOfMatches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count)) // $ regex=nsregex input=input - nsregex.enumerateMatches(in: input, range: NSMakeRange(0, input.utf16.count), using: {a, b, c in } ) // $ regex=nsregex input=input - _ = nsregex.matches(in: input, range: NSMakeRange(0, input.utf16.count)) // $ regex=nsregex input=input - _ = nsregex.firstMatch(in: input, range: NSMakeRange(0, input.utf16.count)) // $ regex=nsregex input=input - _ = nsregex.rangeOfFirstMatch(in: input, range: NSMakeRange(0, input.utf16.count)) // $ regex=nsregex input=input - _ = nsregex.replaceMatches(in: NSMutableString(string: input), range: NSMakeRange(0, input.utf16.count), withTemplate: "") // $ regex=nsregex input="call to NSString.init(string:)" - _ = nsregex.stringByReplacingMatches(in: input, range: NSMakeRange(0, input.utf16.count), withTemplate: "") // $ regex=nsregex input=input + _ = nsregex.numberOfMatches(in: input, options: [], range: NSRange(location: 0, length: input.utf16.count)) // $ regex=.* input=input + nsregex.enumerateMatches(in: input, range: NSMakeRange(0, input.utf16.count), using: {a, b, c in } ) // $ regex=.* input=input + _ = nsregex.matches(in: input, range: NSMakeRange(0, input.utf16.count)) // $ regex=.* input=input + _ = nsregex.firstMatch(in: input, range: NSMakeRange(0, input.utf16.count)) // $ regex=.* input=input + _ = nsregex.rangeOfFirstMatch(in: input, range: NSMakeRange(0, input.utf16.count)) // $ regex=.* input=input + _ = nsregex.replaceMatches(in: NSMutableString(string: input), range: NSMakeRange(0, input.utf16.count), withTemplate: "") // $ regex=.* input="call to NSString.init(string:)" + _ = nsregex.stringByReplacingMatches(in: input, range: NSMakeRange(0, input.utf16.count), withTemplate: "") // $ regex=.* input=input // --- NSString --- let inputNS = NSString(string: "abcdef") - _ = inputNS.range(of: "*", options: .regularExpression) // $ MISSING: regex=nsregex input=inputNS - _ = inputNS.replacingOccurrences(of: ".*", with: "", options: .regularExpression, range: NSMakeRange(0, inputNS.length)) // $ MISSING: regex=nsregex input=inputNS + _ = inputNS.range(of: "*", options: .regularExpression) // $ MISSING: regex=.* input=inputNS + _ = inputNS.replacingOccurrences(of: ".*", with: "", options: .regularExpression, range: NSMakeRange(0, inputNS.length)) // $ MISSING: regex=.* input=inputNS + + // --- flow --- + + let either_regex = try Regex(b ? ".*" : ".+") + _ = try either_regex.firstMatch(in: input) // $ regex=.* regex=.+ input=input + + let base_str = "a" + let append_regex = try Regex(base_str + "b") + _ = try append_regex.firstMatch(in: input) // $ input=input MISSING: regex=ab } From c5405688f4a993496dac59c1b3d59118c2dadca7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 12 Jun 2023 18:00:24 +0100 Subject: [PATCH 113/364] Swift: Add real world test cases. --- .../regex/licenses/ANodeBlog-LICENSE | 201 ++++++++++++++++++ .../regex/licenses/CodeMirror-LICENSE | 21 ++ .../regex/licenses/Prism-LICENSE | 21 ++ .../regex/licenses/Prototype.js-LICENSE | 16 ++ .../regex/licenses/brace-expansion-LICENSE | 21 ++ .../library-tests/regex/licenses/jest-LICENSE | 23 ++ .../regex/licenses/knockout-LICENSE | 22 ++ .../regex/licenses/marked-LICENSE | 43 ++++ .../library-tests/regex/redos_variants.swift | 57 ++++- swift/ql/test/library-tests/regex/regex.ql | 34 +-- swift/ql/test/library-tests/regex/regex.swift | 2 + 11 files changed, 444 insertions(+), 17 deletions(-) create mode 100644 swift/ql/test/library-tests/regex/licenses/ANodeBlog-LICENSE create mode 100644 swift/ql/test/library-tests/regex/licenses/CodeMirror-LICENSE create mode 100644 swift/ql/test/library-tests/regex/licenses/Prism-LICENSE create mode 100644 swift/ql/test/library-tests/regex/licenses/Prototype.js-LICENSE create mode 100644 swift/ql/test/library-tests/regex/licenses/brace-expansion-LICENSE create mode 100644 swift/ql/test/library-tests/regex/licenses/jest-LICENSE create mode 100644 swift/ql/test/library-tests/regex/licenses/knockout-LICENSE create mode 100644 swift/ql/test/library-tests/regex/licenses/marked-LICENSE diff --git a/swift/ql/test/library-tests/regex/licenses/ANodeBlog-LICENSE b/swift/ql/test/library-tests/regex/licenses/ANodeBlog-LICENSE new file mode 100644 index 00000000000..8dada3edaf5 --- /dev/null +++ b/swift/ql/test/library-tests/regex/licenses/ANodeBlog-LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/swift/ql/test/library-tests/regex/licenses/CodeMirror-LICENSE b/swift/ql/test/library-tests/regex/licenses/CodeMirror-LICENSE new file mode 100644 index 00000000000..ff7db4b99f5 --- /dev/null +++ b/swift/ql/test/library-tests/regex/licenses/CodeMirror-LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2017 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/swift/ql/test/library-tests/regex/licenses/Prism-LICENSE b/swift/ql/test/library-tests/regex/licenses/Prism-LICENSE new file mode 100644 index 00000000000..528949f42d9 --- /dev/null +++ b/swift/ql/test/library-tests/regex/licenses/Prism-LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright (c) 2012 Lea Verou + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/swift/ql/test/library-tests/regex/licenses/Prototype.js-LICENSE b/swift/ql/test/library-tests/regex/licenses/Prototype.js-LICENSE new file mode 100644 index 00000000000..05789cf0190 --- /dev/null +++ b/swift/ql/test/library-tests/regex/licenses/Prototype.js-LICENSE @@ -0,0 +1,16 @@ +Copyright (c) 2005-2010 Sam Stephenson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/swift/ql/test/library-tests/regex/licenses/brace-expansion-LICENSE b/swift/ql/test/library-tests/regex/licenses/brace-expansion-LICENSE new file mode 100644 index 00000000000..de3226673c3 --- /dev/null +++ b/swift/ql/test/library-tests/regex/licenses/brace-expansion-LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2013 Julian Gruber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/swift/ql/test/library-tests/regex/licenses/jest-LICENSE b/swift/ql/test/library-tests/regex/licenses/jest-LICENSE new file mode 100644 index 00000000000..10e779c44ac --- /dev/null +++ b/swift/ql/test/library-tests/regex/licenses/jest-LICENSE @@ -0,0 +1,23 @@ +MIT License + +For Jest software + +Copyright (c) 2014-present, Facebook, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/swift/ql/test/library-tests/regex/licenses/knockout-LICENSE b/swift/ql/test/library-tests/regex/licenses/knockout-LICENSE new file mode 100644 index 00000000000..08a07b1ae8d --- /dev/null +++ b/swift/ql/test/library-tests/regex/licenses/knockout-LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) - http://www.opensource.org/licenses/mit-license.php + +Copyright (c) Steven Sanderson, the Knockout.js team, and other contributors +http://knockoutjs.com/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/swift/ql/test/library-tests/regex/licenses/marked-LICENSE b/swift/ql/test/library-tests/regex/licenses/marked-LICENSE new file mode 100644 index 00000000000..64b41a0e463 --- /dev/null +++ b/swift/ql/test/library-tests/regex/licenses/marked-LICENSE @@ -0,0 +1,43 @@ +# License information + +## Contribution License Agreement + +If you contribute code to this project, you are implicitly allowing your code +to be distributed under the MIT license. You are also implicitly verifying that +all code is your original work. `` + +## Marked + +Copyright (c) 2011-2018, Christopher Jeffrey (https://github.com/chjj/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## Markdown + +Copyright © 2004, John Gruber +http://daringfireball.net/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name “Markdown” nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +This software is provided by the copyright holders and contributors “as is” and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 6d5ffb886f6..ad3cdea55b4 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -30,11 +30,15 @@ extension String { } // --- tests --- +// +// the focus for these tests is different vulnerable and non-vulnerable regexp strings. func myRegexpVariantsTests(myUrl: URL) throws { let tainted = String(contentsOf: myUrl) // tainted let untainted = "abcdef" + // basic cases: + _ = try Regex(".*").firstMatch(in: tainted) // $ regex=.* input=tainted _ = try Regex("a*b").firstMatch(in: tainted) // $ regex=a*b input=tainted @@ -47,8 +51,59 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex=(a|aa?)*b input=tainted redos-vulnerable= // from the qhelp: + _ = try Regex("^_(__|.)+_$").firstMatch(in: tainted) // $ regex=^_(__|.)+_$ input=tainted redos-vulnerable= _ = try Regex("^_(__|[^_])+_$").firstMatch(in: tainted) // $ regex=^_(__|[^_])+_$ input=tainted - // TODO: test more variant expressions. + // real world cases: + + // NOT GOOD; attack: "_" + "__".repeat(100) + // Adapted from marked (https://github.com/markedjs/marked), which is licensed + // under the MIT license; see file licenses/marked-LICENSE. + _ = try Regex("^\\b_((?:__|[\\s\\S])+?)_\\b|^\\*((?:\\*\\*|[\\s\\S])+?)\\*(?!\\*)").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + // Adapted from marked (https://github.com/markedjs/marked), which is licensed + // under the MIT license; see file licenses/marked-LICENSE. + _ = try Regex("^\\b_((?:__|[^_])+?)_\\b|^\\*((?:\\*\\*|[^*])+?)\\*(?!\\*)").firstMatch(in: tainted) + + // GOOD - there is no witness in the end that could cause the regexp to not match + // Adapted from brace-expansion (https://github.com/juliangruber/brace-expansion), + // which is licensed under the MIT license; see file licenses/brace-expansion-LICENSE. + _ = try Regex("(.*,)+.+").firstMatch(in: tainted) + + // NOT GOOD; attack: " '" + "\\\\".repeat(100) + // Adapted from CodeMirror (https://github.com/codemirror/codemirror), + // which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE. + _ = try Regex("^(?:\\s+(?:\"(?:[^\"\\\\]|\\\\\\\\|\\\\.)+\"|'(?:[^'\\\\]|\\\\\\\\|\\\\.)+'|\\((?:[^)\\\\]|\\\\\\\\|\\\\.)+\\)))?").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + // Adapted from jest (https://github.com/facebook/jest), which is licensed + // under the MIT license; see file licenses/jest-LICENSE. + _ = try Regex("^ *(\\S.*\\|.*)\\n *([-:]+ *\\|[-| :]*)\\n((?:.*\\|.*(?:\\n|$))*)\\n*").firstMatch(in: tainted) + + // NOT GOOD; attack: "/" + "\\/a".repeat(100) + // Adapted from ANodeBlog (https://github.com/gefangshuai/ANodeBlog), + // which is licensed under the Apache License 2.0; see file licenses/ANodeBlog-LICENSE. + _ = try Regex("\\/(?![ *])(\\\\\\/|.)*?\\/[gim]*(?=\\W|$)").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD; attack: "##".repeat(100) + "\na" + // Adapted from CodeMirror (https://github.com/codemirror/codemirror), + // which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE. + _ = try Regex("^([\\s\\[\\{\\(]|#.*)*$").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD; attack: "a" + "[]".repeat(100) + ".b\n" + // Adapted from Knockout (https://github.com/knockout/knockout), which is + // licensed under the MIT license; see file licenses/knockout-LICENSE + _ = try Regex("^[\\_$a-z][\\_$a-z0-9]*(\\[.*?\\])*(\\.[\\_$a-z][\\_$a-z0-9]*(\\[.*?\\])*)*$").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD; attack: "[" + "][".repeat(100) + "]!" + // Adapted from Prototype.js (https://github.com/prototypejs/prototype), which + // is licensed under the MIT license; see file licenses/Prototype.js-LICENSE. + _ = try Regex("(([\\w#:.~>+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD; attack: "'" + "\\a".repeat(100) + '"' + // Adapted from Prism (https://github.com/PrismJS/prism), which is licensed + // under the MIT license; see file licenses/Prism-LICENSE. + _ = try Regex("(\"|')(\\\\?.)*?\\1").firstMatch(in: tainted) // $ redos-vulnerable= } diff --git a/swift/ql/test/library-tests/regex/regex.ql b/swift/ql/test/library-tests/regex/regex.ql index 9c055790f0a..4a40c59aebc 100644 --- a/swift/ql/test/library-tests/regex/regex.ql +++ b/swift/ql/test/library-tests/regex/regex.ql @@ -11,22 +11,6 @@ module RegexTest implements TestSig { string getARelevantTag() { result = ["regex", "input", "redos-vulnerable"] } predicate hasActualResult(Location location, string element, string tag, string value) { - exists(RegexEval eval, Expr regex | - eval.getARegex() = regex and - location = eval.getLocation() and - element = eval.toString() and - tag = "regex" and - value = quote(regex.toString()) - ) - or - exists(RegexEval eval, Expr input | - eval.getStringInput() = input and - location = input.getLocation() and - element = input.toString() and - tag = "input" and - value = quote(input.toString()) - ) - or exists(TreeView::RegExpTerm t, string pump, State s, string prefixMsg | hasReDoSResult(t, pump, s, prefixMsg) and location = t.getLocation() and @@ -35,6 +19,24 @@ module RegexTest implements TestSig { value = "" ) } + + predicate hasOptionalResult(Location location, string element, string tag, string value) { + exists(RegexEval eval, Expr input | + eval.getStringInput() = input and + location = input.getLocation() and + element = input.toString() and + tag = "input" and + value = quote(input.toString()) + ) + or + exists(RegexEval eval, Expr regex | + eval.getARegex() = regex and + location = eval.getLocation() and + element = eval.toString() and + tag = "regex" and + value = quote(regex.toString()) + ) + } } import MakeTest diff --git a/swift/ql/test/library-tests/regex/regex.swift b/swift/ql/test/library-tests/regex/regex.swift index 088b62a040f..c3dbb6da172 100644 --- a/swift/ql/test/library-tests/regex/regex.swift +++ b/swift/ql/test/library-tests/regex/regex.swift @@ -95,6 +95,8 @@ class NSRegularExpression : NSObject { } // --- tests --- +// +// the focus for these tests is different ways of evaluating regexps. func myRegexpMethodsTests(b: Bool) throws { let input = "abcdef" From 44eb7bf6427a0536f6a31258b6efcfb2bedb3d6e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 12 Jun 2023 19:24:52 +0100 Subject: [PATCH 114/364] Swift: Import more test cases from other languages (this highlights some issues). --- .../library-tests/regex/redos_variants.swift | 357 +++++++++++++++++- 1 file changed, 356 insertions(+), 1 deletion(-) diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index ad3cdea55b4..ee3d6e9d29a 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -35,7 +35,6 @@ extension String { func myRegexpVariantsTests(myUrl: URL) throws { let tainted = String(contentsOf: myUrl) // tainted - let untainted = "abcdef" // basic cases: @@ -106,4 +105,360 @@ func myRegexpVariantsTests(myUrl: URL) throws { // Adapted from Prism (https://github.com/PrismJS/prism), which is licensed // under the MIT license; see file licenses/Prism-LICENSE. _ = try Regex("(\"|')(\\\\?.)*?\\1").firstMatch(in: tainted) // $ redos-vulnerable= + + // more cases: + + // GOOD + _ = try Regex("(\\r\\n|\\r|\\n)+").firstMatch(in: tainted) + + // GOOD + _ = try Regex("(a|.)*").firstMatch(in: tainted) + + // Testing the NFA - only some of the below are detected. + _ = try Regex("^([a-z]+)+$").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex("^([a-z]*)*$").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex("^([a-zA-Z0-9])(([\\\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex("^(([a-z])+.)+[A-Z]([a-z])+$").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(b|a?b)*c").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("(.|\\n)*!").firstMatch(in: tainted) + + // NOT GOOD; attack: "\n".repeat(100) + "." TODO: investigate, we should be getting this one. + _ = try Regex("(?s)(.|\\n)*!").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + + // GOOD + _ = try Regex("([\\w.]+)*").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(([\\s\\S]|[^a])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD - there is no witness in the end that could cause the regexp to not match + _ = try Regex("([^\"']+)*").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("((.|[^a])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("((a|[^a])*)\"").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("((b|[^a])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((G|[^a])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(([0-9]|[^a])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD (missing) + _ = try Regex("(?:=(?:([!#\\$%&'\\*\\+\\-\\.\\^_`\\|~0-9A-Za-z]+)|\"((?:\\\\[\\x00-\\x7f]|[^\\x00-\\x08\\x0a-\\x1f\\x7f\"])*)\"))?").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + + // NOT GOOD (missing) + _ = try Regex("\"((?:\\\\[\\x00-\\x7f]|[^\\x00-\\x08\\x0a-\\x1f\\x7f\"])*)\"").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + + // GOOD + _ = try Regex("\"((?:\\\\[\\x00-\\x7f]|[^\\x00-\\x08\\x0a-\\x1f\\x7f\"\\\\])*)\"").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("(([a-z]|[d-h])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(([^a-z]|[^0-9])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((\\d|[0-9])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((\\s|\\s)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((\\w|G)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("((\\s|\\d)*)\"").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("((\\d|\\w)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((\\d|5)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((\\s|[\\f])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD - but not detected (likely because \v is a character class in Java rather than a specific character in other langs) + _ = try Regex("((\\s|[\\v]|\\\\v)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((\\f|[\\f])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((\\W|\\D)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((\\S|\\w)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((\\S|[\\w])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((1s|[\\da-z])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((0|[\\d])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(([\\d]+)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD - there is no witness in the end that could cause the regexp to not match + _ = try Regex("(\\d+(X\\d+)?)+").firstMatch(in: tainted) + + // GOOD - there is no witness in the end that could cause the regexp to not match + _ = try Regex("([0-9]+(X[0-9]*)?)*").firstMatch(in: tainted) + + // GOOD + _ = try Regex("^([^>]+)*(>|$)").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("^([^>a]+)*(>|$)").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(\\n\\s*)+$").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("^(?:\\s+|#.*|\\(\\?#[^)]*\\))*(?:[?*+]|\\{\\d+(?:,\\d*)?})").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("\\{\\[\\s*([a-zA-Z]+)\\(([a-zA-Z]+)\\)((\\s*([a-zA-Z]+)\\: ?([ a-zA-Z{}]+),?)+)*\\s*\\]\\}").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(a+|b+|c+)*c").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(((a+a?)*)+b+)").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(a+)+bbbb").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("(a+)+aaaaa*a+").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("(a+)+aaaaa$").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("(\\n+)+\\n\\n").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("(\\n+)+\\n\\n$").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("([^X]+)*$").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(([^X]b)+)*$").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("(([^X]b)+)*($|[^X]b)").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("(([^X]b)+)*($|[^X]c)").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("((ab)+)*ababab").firstMatch(in: tainted) + + // GOOD + _ = try Regex("((ab)+)*abab(ab)*(ab)+").firstMatch(in: tainted) + + // GOOD + _ = try Regex("((ab)+)*").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("((ab)+)*$").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("((ab)+)*[a1][b1][a2][b2][a3][b3]").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("([\\n\\s]+)*(.)").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD - any witness passes through the accept state. + _ = try Regex("(A*A*X)*").firstMatch(in: tainted) + + // GOOD + _ = try Regex("([^\\\\\\]]+)*").firstMatch(in: tainted) + + // NOT GOOD TODO: QL evaluation times out (for test, at 5 minutes) +// _ = try Regex("(\\w*foobarbaz\\w*foobarbaz\\w*foobarbaz\\w*foobarbaz\\s*foobarbaz\\d*foobarbaz\\w*)+-").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD (but cannot currently construct a prefix) + _ = try Regex("a{2,3}(b+)+X").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD (and a good prefix test) + _ = try Regex("^<(\\w+)((?:\\s+\\w+(?:\\s*=\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*)\\s*(\\/?)>").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("(a+)*[\\s\\S][\\s\\S][\\s\\S]?").firstMatch(in: tainted) + + // GOOD - but we fail to see that repeating the attack string ends in the "accept any" state (due to not parsing the range `[\s\S]{2,3}`). + _ = try Regex("(a+)*[\\s\\S]{2,3}").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + + // GOOD - but we spuriously conclude that a rejecting suffix exists (due to not parsing the range `[\s\S]{2,}` when constructing the NFA). + _ = try Regex("(a+)*([\\s\\S]{2,}|X)$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + + // GOOD + _ = try Regex("(a+)*([\\s\\S]*|X)$").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("((a+)*$|[\\s\\S]+)").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD - but still flagged. The only change compared to the above is the order of alternatives, which we don't model. + _ = try Regex("([\\s\\S]+|(a+)*$)").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + + // GOOD + _ = try Regex("((;|^)a+)+$").firstMatch(in: tainted) + + // NOT GOOD (a good prefix test) + _ = try Regex("(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("^ab(c+)+$").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(\\d(\\s+)*){20}").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD - but we spuriously conclude that a rejecting suffix exists. + _ = try Regex("(([^/]|X)+)(\\/[\\s\\S]*)*$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + + // GOOD - but we spuriously conclude that a rejecting suffix exists. + _ = try Regex("^((x([^Y]+)?)*(Y|$))").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + + // NOT GOOD + _ = try Regex("(a*)+b").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("foo([\\w-]*)+bar").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("((ab)*)+c").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("(a?a?)*b").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("(a?)*b").firstMatch(in: tainted) + + // NOT GOOD - but not detected + _ = try Regex("(c?a?)*b").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + + // NOT GOOD + _ = try Regex("(?:a|a?)+b").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD - but not detected. + _ = try Regex("(a?b?)*$").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + + // NOT GOOD + _ = try Regex("PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("^((a)+\\w)+$").firstMatch(in: tainted) // $ redos-vulnerable= + + // NOT GOOD + _ = try Regex("^(b+.)+$").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("a*b").firstMatch(in: tainted) + + // All 4 bad combinations of nested * and + + _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex("(a+)*b").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex("(a*)+b").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex("(a+)+b").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("(a|b)+").firstMatch(in: tainted) + _ = try Regex("(?:[\\s;,\"'<>(){}|\\[\\]@=+*]|:(?![/\\\\]))+").firstMatch(in: tainted) + + // TODO: investigate; these were marked `hasParseFailure` + _ = try Regex("^((?:a{|-)|\\w\\{)+X$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex("^((?:a{0|-)|\\w\\{\\d)+X$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex("^((?:a{0,|-)|\\w\\{\\d,)+X$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex("^((?:a{0,2|-)|\\w\\{\\d,\\d)+X$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + + // GOOD + _ = try Regex("^((?:a{0,2}|-)|\\w\\{\\d,\\d\\})+X$").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("X(\\u0061|a)*Y").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("X(\\u0061|b)+Y").firstMatch(in: tainted) + + // NOT GOOD TODO: we should get this one + _ = try Regex("X(\\x61|a)*Y").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + + // GOOD + _ = try Regex("X(\\x61|b)+Y").firstMatch(in: tainted) + + // NOT GOOD TODO: we should get this one + _ = try Regex("X(\\x{061}|a)*Y").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + + // GOOD + _ = try Regex("X(\\x{061}|b)+Y").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("X(\\p{Digit}|7)*Y").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("X(\\p{Digit}|b)+Y").firstMatch(in: tainted) + + // NOT GOOD + _ = try Regex("X(\\P{Digit}|b)*Y").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + _ = try Regex("X(\\P{Digit}|7)+Y").firstMatch(in: tainted) + + // NOT GOOD TODO: we should get this one + _ = try Regex("X(\\p{IsDigit}|7)*Y").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + + // GOOD + _ = try Regex("X(\\p{IsDigit}|b)+Y").firstMatch(in: tainted) + + // NOT GOOD - but not detected + _ = try Regex("X(\\p{Alpha}|a)*Y").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + + // GOOD + _ = try Regex("X(\\p{Alpha}|7)+Y").firstMatch(in: tainted) + + // GOOD + _ = try Regex("(\"[^\"]*?\"|[^\"\\s]+)+(?=\\s*|\\s*$)").firstMatch(in: tainted) + + // BAD + _ = try Regex("/(\"[^\"]*?\"|[^\"\\s]+)+(?=\\s*|\\s*$)X").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex("/(\"[^\"]*?\"|[^\"\\s]+)+(?=X)").firstMatch(in: tainted) // $ redos-vulnerable= + + // BAD + _ = try Regex("\\A(\\d|0)*x").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex("(\\d|0)*\\Z").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex("\\b(\\d|0)*x").firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD - possessive quantifiers don't backtrack + _ = try Regex("(a*+)*+b").firstMatch(in: tainted) + _ = try Regex("(a*)*+b").firstMatch(in: tainted) + _ = try Regex("(a*+)*b").firstMatch(in: tainted) + + // BAD + _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ redos-vulnerable= + + // BAD - but not detected due to the way possessive quantifiers are approximated + _ = try Regex("((aa|a*+)b)*c").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= } From 63ab4788e0c8dd1ec5301aa9003f0eb406996d5f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 13 Jun 2023 00:00:49 +0100 Subject: [PATCH 115/364] Swift: Flag parse failures in the test. --- .../test/library-tests/regex/redos_variants.swift | 14 +++++++------- swift/ql/test/library-tests/regex/regex.ql | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index ee3d6e9d29a..31fc0876551 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -130,7 +130,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("(.|\\n)*!").firstMatch(in: tainted) // NOT GOOD; attack: "\n".repeat(100) + "." TODO: investigate, we should be getting this one. - _ = try Regex("(?s)(.|\\n)*!").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex("(?s)(.|\\n)*!").firstMatch(in: tainted) // $ hasParseFailure MISSING: redos-vulnerable= // GOOD _ = try Regex("([\\w.]+)*").firstMatch(in: tainted) @@ -410,10 +410,10 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("X(\\x61|b)+Y").firstMatch(in: tainted) // NOT GOOD TODO: we should get this one - _ = try Regex("X(\\x{061}|a)*Y").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex("X(\\x{061}|a)*Y").firstMatch(in: tainted) // $ hasParseFailure= MISSING: redos-vulnerable= // GOOD - _ = try Regex("X(\\x{061}|b)+Y").firstMatch(in: tainted) + _ = try Regex("X(\\x{061}|b)+Y").firstMatch(in: tainted) // $ hasParseFailure // NOT GOOD _ = try Regex("X(\\p{Digit}|7)*Y").firstMatch(in: tainted) // $ redos-vulnerable= @@ -452,13 +452,13 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("\\b(\\d|0)*x").firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - possessive quantifiers don't backtrack - _ = try Regex("(a*+)*+b").firstMatch(in: tainted) - _ = try Regex("(a*)*+b").firstMatch(in: tainted) - _ = try Regex("(a*+)*b").firstMatch(in: tainted) + _ = try Regex("(a*+)*+b").firstMatch(in: tainted) // $ hasParseFailure + _ = try Regex("(a*)*+b").firstMatch(in: tainted) // $ hasParseFailure + _ = try Regex("(a*+)*b").firstMatch(in: tainted) // $ hasParseFailure // BAD _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ redos-vulnerable= // BAD - but not detected due to the way possessive quantifiers are approximated - _ = try Regex("((aa|a*+)b)*c").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex("((aa|a*+)b)*c").firstMatch(in: tainted) // $ hasParseFailure MISSING: redos-vulnerable= } diff --git a/swift/ql/test/library-tests/regex/regex.ql b/swift/ql/test/library-tests/regex/regex.ql index 4a40c59aebc..8730b6539ce 100644 --- a/swift/ql/test/library-tests/regex/regex.ql +++ b/swift/ql/test/library-tests/regex/regex.ql @@ -1,5 +1,6 @@ import swift import codeql.swift.regex.Regex +private import codeql.swift.regex.internal.ParseRegex private import codeql.swift.regex.RegexTreeView::RegexTreeView as TreeView import codeql.regex.nfa.ExponentialBackTracking::Make import TestUtilities.InlineExpectationsTest @@ -8,7 +9,7 @@ bindingset[s] string quote(string s) { if s.matches("% %") then result = "\"" + s + "\"" else result = s } module RegexTest implements TestSig { - string getARelevantTag() { result = ["regex", "input", "redos-vulnerable"] } + string getARelevantTag() { result = ["regex", "input", "redos-vulnerable", "hasParseFailure"] } predicate hasActualResult(Location location, string element, string tag, string value) { exists(TreeView::RegExpTerm t, string pump, State s, string prefixMsg | @@ -18,6 +19,15 @@ module RegexTest implements TestSig { tag = "redos-vulnerable" and value = "" ) + or + exists(RegexEval eval, RegExp regex | + eval.getARegex() = regex and + regex.failedToParse(_) and + location = eval.getLocation() and + element = eval.toString() and + tag = "hasParseFailure" and + value = "" + ) } predicate hasOptionalResult(Location location, string element, string tag, string value) { @@ -29,7 +39,7 @@ module RegexTest implements TestSig { value = quote(input.toString()) ) or - exists(RegexEval eval, Expr regex | + exists(RegexEval eval, RegExp regex | eval.getARegex() = regex and location = eval.getLocation() and element = eval.toString() and From f93bf6ad223dbcae07e0b9b27411b73dfebf6112 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 13 Jun 2023 17:38:47 +0100 Subject: [PATCH 116/364] Swift: Escape the test cases in a better way (so escape characters don't obscure what's going on). --- .../library-tests/regex/redos_variants.swift | 174 +++++++++--------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 31fc0876551..49578d91500 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -59,12 +59,12 @@ func myRegexpVariantsTests(myUrl: URL) throws { // NOT GOOD; attack: "_" + "__".repeat(100) // Adapted from marked (https://github.com/markedjs/marked), which is licensed // under the MIT license; see file licenses/marked-LICENSE. - _ = try Regex("^\\b_((?:__|[\\s\\S])+?)_\\b|^\\*((?:\\*\\*|[\\s\\S])+?)\\*(?!\\*)").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD // Adapted from marked (https://github.com/markedjs/marked), which is licensed // under the MIT license; see file licenses/marked-LICENSE. - _ = try Regex("^\\b_((?:__|[^_])+?)_\\b|^\\*((?:\\*\\*|[^*])+?)\\*(?!\\*)").firstMatch(in: tainted) + _ = try Regex(#"^\b_((?:__|[^_])+?)_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)"#).firstMatch(in: tainted) // GOOD - there is no witness in the end that could cause the regexp to not match // Adapted from brace-expansion (https://github.com/juliangruber/brace-expansion), @@ -74,42 +74,42 @@ func myRegexpVariantsTests(myUrl: URL) throws { // NOT GOOD; attack: " '" + "\\\\".repeat(100) // Adapted from CodeMirror (https://github.com/codemirror/codemirror), // which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE. - _ = try Regex("^(?:\\s+(?:\"(?:[^\"\\\\]|\\\\\\\\|\\\\.)+\"|'(?:[^'\\\\]|\\\\\\\\|\\\\.)+'|\\((?:[^)\\\\]|\\\\\\\\|\\\\.)+\\)))?").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD // Adapted from jest (https://github.com/facebook/jest), which is licensed // under the MIT license; see file licenses/jest-LICENSE. - _ = try Regex("^ *(\\S.*\\|.*)\\n *([-:]+ *\\|[-| :]*)\\n((?:.*\\|.*(?:\\n|$))*)\\n*").firstMatch(in: tainted) + _ = try Regex(#"^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*"#).firstMatch(in: tainted) // NOT GOOD; attack: "/" + "\\/a".repeat(100) // Adapted from ANodeBlog (https://github.com/gefangshuai/ANodeBlog), // which is licensed under the Apache License 2.0; see file licenses/ANodeBlog-LICENSE. - _ = try Regex("\\/(?![ *])(\\\\\\/|.)*?\\/[gim]*(?=\\W|$)").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD; attack: "##".repeat(100) + "\na" // Adapted from CodeMirror (https://github.com/codemirror/codemirror), // which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE. - _ = try Regex("^([\\s\\[\\{\\(]|#.*)*$").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^([\s\[\{\(]|#.*)*$"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD; attack: "a" + "[]".repeat(100) + ".b\n" // Adapted from Knockout (https://github.com/knockout/knockout), which is // licensed under the MIT license; see file licenses/knockout-LICENSE - _ = try Regex("^[\\_$a-z][\\_$a-z0-9]*(\\[.*?\\])*(\\.[\\_$a-z][\\_$a-z0-9]*(\\[.*?\\])*)*$").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD; attack: "[" + "][".repeat(100) + "]!" // Adapted from Prototype.js (https://github.com/prototypejs/prototype), which // is licensed under the MIT license; see file licenses/Prototype.js-LICENSE. - _ = try Regex("(([\\w#:.~>+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD; attack: "'" + "\\a".repeat(100) + '"' // Adapted from Prism (https://github.com/PrismJS/prism), which is licensed // under the MIT license; see file licenses/Prism-LICENSE. - _ = try Regex("(\"|')(\\\\?.)*?\\1").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"("|')(\\?.)*?\1"#).firstMatch(in: tainted) // $ redos-vulnerable= // more cases: // GOOD - _ = try Regex("(\\r\\n|\\r|\\n)+").firstMatch(in: tainted) + _ = try Regex(#"(\r\n|\r|\n)+"#).firstMatch(in: tainted) // GOOD _ = try Regex("(a|.)*").firstMatch(in: tainted) @@ -117,7 +117,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { // Testing the NFA - only some of the below are detected. _ = try Regex("^([a-z]+)+$").firstMatch(in: tainted) // $ redos-vulnerable= _ = try Regex("^([a-z]*)*$").firstMatch(in: tainted) // $ redos-vulnerable= - _ = try Regex("^([a-zA-Z0-9])(([\\\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$"#).firstMatch(in: tainted) // $ redos-vulnerable= _ = try Regex("^(([a-z])+.)+[A-Z]([a-z])+$").firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD @@ -127,100 +127,100 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - _ = try Regex("(.|\\n)*!").firstMatch(in: tainted) + _ = try Regex(#"(.|\n)*!"#).firstMatch(in: tainted) // NOT GOOD; attack: "\n".repeat(100) + "." TODO: investigate, we should be getting this one. - _ = try Regex("(?s)(.|\\n)*!").firstMatch(in: tainted) // $ hasParseFailure MISSING: redos-vulnerable= + _ = try Regex(#"(?s)(.|\n)*!"#).firstMatch(in: tainted) // $ hasParseFailure MISSING: redos-vulnerable= // GOOD - _ = try Regex("([\\w.]+)*").firstMatch(in: tainted) + _ = try Regex(#"([\w.]+)*"#).firstMatch(in: tainted) // NOT GOOD _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("(([\\s\\S]|[^a])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(([\s\S]|[^a])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - there is no witness in the end that could cause the regexp to not match - _ = try Regex("([^\"']+)*").firstMatch(in: tainted) + _ = try Regex(#"([^"']+)*"#).firstMatch(in: tainted) // NOT GOOD - _ = try Regex("((.|[^a])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((.|[^a])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - _ = try Regex("((a|[^a])*)\"").firstMatch(in: tainted) + _ = try Regex(#"((a|[^a])*)""#).firstMatch(in: tainted) // NOT GOOD - _ = try Regex("((b|[^a])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((b|[^a])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((G|[^a])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((G|[^a])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("(([0-9]|[^a])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(([0-9]|[^a])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD (missing) - _ = try Regex("(?:=(?:([!#\\$%&'\\*\\+\\-\\.\\^_`\\|~0-9A-Za-z]+)|\"((?:\\\\[\\x00-\\x7f]|[^\\x00-\\x08\\x0a-\\x1f\\x7f\"])*)\"))?").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex(#"(?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"))?"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // NOT GOOD (missing) - _ = try Regex("\"((?:\\\\[\\x00-\\x7f]|[^\\x00-\\x08\\x0a-\\x1f\\x7f\"])*)\"").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex(#""((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)""#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD - _ = try Regex("\"((?:\\\\[\\x00-\\x7f]|[^\\x00-\\x08\\x0a-\\x1f\\x7f\"\\\\])*)\"").firstMatch(in: tainted) + _ = try Regex(#""((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*)""#).firstMatch(in: tainted) // NOT GOOD - _ = try Regex("(([a-z]|[d-h])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(([a-z]|[d-h])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("(([^a-z]|[^0-9])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(([^a-z]|[^0-9])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((\\d|[0-9])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\d|[0-9])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((\\s|\\s)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\s|\s)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((\\w|G)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\w|G)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - _ = try Regex("((\\s|\\d)*)\"").firstMatch(in: tainted) + _ = try Regex(#"((\s|\d)*)""#).firstMatch(in: tainted) // NOT GOOD - _ = try Regex("((\\d|\\w)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\d|\w)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((\\d|5)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\d|5)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((\\s|[\\f])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\s|[\f])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - but not detected (likely because \v is a character class in Java rather than a specific character in other langs) - _ = try Regex("((\\s|[\\v]|\\\\v)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\s|[\v]|\\v)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((\\f|[\\f])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\f|[\f])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((\\W|\\D)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\W|\D)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((\\S|\\w)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\S|\w)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((\\S|[\\w])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\S|[\w])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((1s|[\\da-z])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((1s|[\da-z])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("((0|[\\d])*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((0|[\d])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("(([\\d]+)*)\"").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(([\d]+)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - there is no witness in the end that could cause the regexp to not match - _ = try Regex("(\\d+(X\\d+)?)+").firstMatch(in: tainted) + _ = try Regex(#"(\d+(X\d+)?)+"#).firstMatch(in: tainted) // GOOD - there is no witness in the end that could cause the regexp to not match _ = try Regex("([0-9]+(X[0-9]*)?)*").firstMatch(in: tainted) @@ -232,13 +232,13 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("^([^>a]+)*(>|$)").firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("(\\n\\s*)+$").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(\n\s*)+$"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("^(?:\\s+|#.*|\\(\\?#[^)]*\\))*(?:[?*+]|\\{\\d+(?:,\\d*)?})").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|\{\d+(?:,\d*)?})"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("\\{\\[\\s*([a-zA-Z]+)\\(([a-zA-Z]+)\\)((\\s*([a-zA-Z]+)\\: ?([ a-zA-Z{}]+),?)+)*\\s*\\]\\}").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD _ = try Regex("(a+|b+|c+)*c").firstMatch(in: tainted) // $ redos-vulnerable= @@ -256,10 +256,10 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("(a+)+aaaaa$").firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - _ = try Regex("(\\n+)+\\n\\n").firstMatch(in: tainted) + _ = try Regex(#"(\n+)+\n\n"#).firstMatch(in: tainted) // NOT GOOD - _ = try Regex("(\\n+)+\\n\\n$").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(\n+)+\n\n$"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD _ = try Regex("([^X]+)*$").firstMatch(in: tainted) // $ redos-vulnerable= @@ -289,40 +289,40 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("((ab)+)*[a1][b1][a2][b2][a3][b3]").firstMatch(in: tainted) // NOT GOOD - _ = try Regex("([\\n\\s]+)*(.)").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"([\n\s]+)*(.)"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - any witness passes through the accept state. _ = try Regex("(A*A*X)*").firstMatch(in: tainted) // GOOD - _ = try Regex("([^\\\\\\]]+)*").firstMatch(in: tainted) + _ = try Regex(#"([^\\\]]+)*"#).firstMatch(in: tainted) // NOT GOOD TODO: QL evaluation times out (for test, at 5 minutes) -// _ = try Regex("(\\w*foobarbaz\\w*foobarbaz\\w*foobarbaz\\w*foobarbaz\\s*foobarbaz\\d*foobarbaz\\w*)+-").firstMatch(in: tainted) // $ redos-vulnerable= +// _ = try Regex(#"(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD (but cannot currently construct a prefix) _ = try Regex("a{2,3}(b+)+X").firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD (and a good prefix test) - _ = try Regex("^<(\\w+)((?:\\s+\\w+(?:\\s*=\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*)\\s*(\\/?)>").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - _ = try Regex("(a+)*[\\s\\S][\\s\\S][\\s\\S]?").firstMatch(in: tainted) + _ = try Regex(#"(a+)*[\s\S][\s\S][\s\S]?"#).firstMatch(in: tainted) // GOOD - but we fail to see that repeating the attack string ends in the "accept any" state (due to not parsing the range `[\s\S]{2,3}`). - _ = try Regex("(a+)*[\\s\\S]{2,3}").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex(#"(a+)*[\s\S]{2,3}"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= // GOOD - but we spuriously conclude that a rejecting suffix exists (due to not parsing the range `[\s\S]{2,}` when constructing the NFA). - _ = try Regex("(a+)*([\\s\\S]{2,}|X)$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex(#"(a+)*([\s\S]{2,}|X)$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= // GOOD - _ = try Regex("(a+)*([\\s\\S]*|X)$").firstMatch(in: tainted) + _ = try Regex(#"(a+)*([\s\S]*|X)$"#).firstMatch(in: tainted) // NOT GOOD - _ = try Regex("((a+)*$|[\\s\\S]+)").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((a+)*$|[\s\S]+)"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - but still flagged. The only change compared to the above is the order of alternatives, which we don't model. - _ = try Regex("([\\s\\S]+|(a+)*$)").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex(#"([\s\S]+|(a+)*$)"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= // GOOD _ = try Regex("((;|^)a+)+$").firstMatch(in: tainted) @@ -334,10 +334,10 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("^ab(c+)+$").firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("(\\d(\\s+)*){20}").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(\d(\s+)*){20}"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - but we spuriously conclude that a rejecting suffix exists. - _ = try Regex("(([^/]|X)+)(\\/[\\s\\S]*)*$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex(#"(([^/]|X)+)(\/[\s\S]*)*$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= // GOOD - but we spuriously conclude that a rejecting suffix exists. _ = try Regex("^((x([^Y]+)?)*(Y|$))").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= @@ -346,7 +346,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("(a*)+b").firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("foo([\\w-]*)+bar").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"foo([\w-]*)+bar"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD _ = try Regex("((ab)*)+c").firstMatch(in: tainted) // $ redos-vulnerable= @@ -370,7 +370,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)").firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD - _ = try Regex("^((a)+\\w)+$").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^((a)+\w)+$"#).firstMatch(in: tainted) // $ redos-vulnerable= // NOT GOOD _ = try Regex("^(b+.)+$").firstMatch(in: tainted) // $ redos-vulnerable= @@ -386,70 +386,70 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex("(a|b)+").firstMatch(in: tainted) - _ = try Regex("(?:[\\s;,\"'<>(){}|\\[\\]@=+*]|:(?![/\\\\]))+").firstMatch(in: tainted) + _ = try Regex(#"(?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]))+"#).firstMatch(in: tainted) // TODO: investigate; these were marked `hasParseFailure` - _ = try Regex("^((?:a{|-)|\\w\\{)+X$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= - _ = try Regex("^((?:a{0|-)|\\w\\{\\d)+X$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= - _ = try Regex("^((?:a{0,|-)|\\w\\{\\d,)+X$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= - _ = try Regex("^((?:a{0,2|-)|\\w\\{\\d,\\d)+X$").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex(#"^((?:a{|-)|\w\{)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex(#"^((?:a{0|-)|\w\{\d)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex(#"^((?:a{0,|-)|\w\{\d,)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + _ = try Regex(#"^((?:a{0,2|-)|\w\{\d,\d)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= // GOOD - _ = try Regex("^((?:a{0,2}|-)|\\w\\{\\d,\\d\\})+X$").firstMatch(in: tainted) + _ = try Regex(#"^((?:a{0,2}|-)|\w\{\d,\d\})+X$"#).firstMatch(in: tainted) // NOT GOOD - _ = try Regex("X(\\u0061|a)*Y").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"X(\u0061|a)*Y"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - _ = try Regex("X(\\u0061|b)+Y").firstMatch(in: tainted) + _ = try Regex(#"X(\u0061|b)+Y"#).firstMatch(in: tainted) // NOT GOOD TODO: we should get this one - _ = try Regex("X(\\x61|a)*Y").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex(#"X(\x61|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD - _ = try Regex("X(\\x61|b)+Y").firstMatch(in: tainted) + _ = try Regex(#"X(\x61|b)+Y"#).firstMatch(in: tainted) // NOT GOOD TODO: we should get this one - _ = try Regex("X(\\x{061}|a)*Y").firstMatch(in: tainted) // $ hasParseFailure= MISSING: redos-vulnerable= + _ = try Regex(#"X(\x{061}|a)*Y"#).firstMatch(in: tainted) // $ hasParseFailure= MISSING: redos-vulnerable= // GOOD - _ = try Regex("X(\\x{061}|b)+Y").firstMatch(in: tainted) // $ hasParseFailure + _ = try Regex(#"X(\x{061}|b)+Y"#).firstMatch(in: tainted) // $ hasParseFailure // NOT GOOD - _ = try Regex("X(\\p{Digit}|7)*Y").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"X(\p{Digit}|7)*Y"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - _ = try Regex("X(\\p{Digit}|b)+Y").firstMatch(in: tainted) + _ = try Regex(#"X(\p{Digit}|b)+Y"#).firstMatch(in: tainted) // NOT GOOD - _ = try Regex("X(\\P{Digit}|b)*Y").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"X(\P{Digit}|b)*Y"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - _ = try Regex("X(\\P{Digit}|7)+Y").firstMatch(in: tainted) + _ = try Regex(#"X(\P{Digit}|7)+Y"#).firstMatch(in: tainted) // NOT GOOD TODO: we should get this one - _ = try Regex("X(\\p{IsDigit}|7)*Y").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex(#"X(\p{IsDigit}|7)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD - _ = try Regex("X(\\p{IsDigit}|b)+Y").firstMatch(in: tainted) + _ = try Regex(#"X(\p{IsDigit}|b)+Y"#).firstMatch(in: tainted) // NOT GOOD - but not detected - _ = try Regex("X(\\p{Alpha}|a)*Y").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex(#"X(\p{Alpha}|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD - _ = try Regex("X(\\p{Alpha}|7)+Y").firstMatch(in: tainted) + _ = try Regex(#"X(\p{Alpha}|7)+Y"#).firstMatch(in: tainted) // GOOD - _ = try Regex("(\"[^\"]*?\"|[^\"\\s]+)+(?=\\s*|\\s*$)").firstMatch(in: tainted) + _ = try Regex(#"("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)"#).firstMatch(in: tainted) // BAD - _ = try Regex("/(\"[^\"]*?\"|[^\"\\s]+)+(?=\\s*|\\s*$)X").firstMatch(in: tainted) // $ redos-vulnerable= - _ = try Regex("/(\"[^\"]*?\"|[^\"\\s]+)+(?=X)").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"/("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"/("[^"]*?"|[^"\s]+)+(?=X)"#).firstMatch(in: tainted) // $ redos-vulnerable= // BAD - _ = try Regex("\\A(\\d|0)*x").firstMatch(in: tainted) // $ redos-vulnerable= - _ = try Regex("(\\d|0)*\\Z").firstMatch(in: tainted) // $ redos-vulnerable= - _ = try Regex("\\b(\\d|0)*x").firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"\A(\d|0)*x"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(\d|0)*\Z"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"\b(\d|0)*x"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - possessive quantifiers don't backtrack _ = try Regex("(a*+)*+b").firstMatch(in: tainted) // $ hasParseFailure From 8e8a9c8018363f4989647d8058e0929ffa7aaeca Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 13 Jun 2023 17:08:57 +0100 Subject: [PATCH 117/364] Swift: Annotate tests based on real ereal execution findings. Add some relevant variants, remove some duplicates, add the testing script also. --- .../library-tests/regex/redos_variants.swift | 344 ++++++++++++------ swift/ql/test/library-tests/regex/regex.ql | 4 +- swift/ql/test/library-tests/regex/regex.swift | 6 + .../regex/test_the_tests.swift.disabled | 145 ++++++++ 4 files changed, 379 insertions(+), 120 deletions(-) create mode 100644 swift/ql/test/library-tests/regex/test_the_tests.swift.disabled diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 49578d91500..ea63005c495 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -18,6 +18,8 @@ struct Regex : RegexComponent { init(_ pattern: String) throws where Output == AnyRegexOutput { } func firstMatch(in string: String) throws -> Regex.Match? { return nil} + func prefixMatch(in string: String) throws -> Regex.Match? { return nil} + func wholeMatch(in string: String) throws -> Regex.Match? { return nil} typealias RegexOutput = Output } @@ -36,7 +38,8 @@ extension String { func myRegexpVariantsTests(myUrl: URL) throws { let tainted = String(contentsOf: myUrl) // tainted - // basic cases: + // basic cases: + // attack string: "a" x lots + "!" _ = try Regex(".*").firstMatch(in: tainted) // $ regex=.* input=tainted @@ -49,64 +52,74 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("(a|aa?)b").firstMatch(in: tainted) // $ regex=(a|aa?)b input=tainted _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex=(a|aa?)*b input=tainted redos-vulnerable= - // from the qhelp: + // from the qhelp: + // attack string: "_" x lots + "!" _ = try Regex("^_(__|.)+_$").firstMatch(in: tainted) // $ regex=^_(__|.)+_$ input=tainted redos-vulnerable= _ = try Regex("^_(__|[^_])+_$").firstMatch(in: tainted) // $ regex=^_(__|[^_])+_$ input=tainted - // real world cases: + // real world cases: - // NOT GOOD; attack: "_" + "__".repeat(100) - // Adapted from marked (https://github.com/markedjs/marked), which is licensed - // under the MIT license; see file licenses/marked-LICENSE. - _ = try Regex(#"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"#).firstMatch(in: tainted) // $ redos-vulnerable= + // Adapted from marked (https://github.com/markedjs/marked), which is licensed + // under the MIT license; see file licenses/marked-LICENSE. + // GOOD + _ = try Regex(#"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + // BAD + // attack string: "_" + "__".repeat(100) + _ = try Regex(#"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"#).wholeMatch(in: tainted) // $ redos-vulnerable= - // GOOD - // Adapted from marked (https://github.com/markedjs/marked), which is licensed - // under the MIT license; see file licenses/marked-LICENSE. + // GOOD + // Adapted from marked (https://github.com/markedjs/marked), which is licensed + // under the MIT license; see file licenses/marked-LICENSE. _ = try Regex(#"^\b_((?:__|[^_])+?)_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)"#).firstMatch(in: tainted) - // GOOD - there is no witness in the end that could cause the regexp to not match - // Adapted from brace-expansion (https://github.com/juliangruber/brace-expansion), - // which is licensed under the MIT license; see file licenses/brace-expansion-LICENSE. + // GOOD - there is no witness in the end that could cause the regexp to not match + // Adapted from brace-expansion (https://github.com/juliangruber/brace-expansion), + // which is licensed under the MIT license; see file licenses/brace-expansion-LICENSE. _ = try Regex("(.*,)+.+").firstMatch(in: tainted) - // NOT GOOD; attack: " '" + "\\\\".repeat(100) - // Adapted from CodeMirror (https://github.com/codemirror/codemirror), - // which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE. + // BAD + // attack string: " '" + "\\\\".repeat(100) + // Adapted from CodeMirror (https://github.com/codemirror/codemirror), + // which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE. _ = try Regex(#"^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?"#).firstMatch(in: tainted) // $ redos-vulnerable= - // GOOD - // Adapted from jest (https://github.com/facebook/jest), which is licensed - // under the MIT license; see file licenses/jest-LICENSE. + // GOOD + // Adapted from jest (https://github.com/facebook/jest), which is licensed + // under the MIT license; see file licenses/jest-LICENSE. _ = try Regex(#"^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*"#).firstMatch(in: tainted) - // NOT GOOD; attack: "/" + "\\/a".repeat(100) - // Adapted from ANodeBlog (https://github.com/gefangshuai/ANodeBlog), - // which is licensed under the Apache License 2.0; see file licenses/ANodeBlog-LICENSE. + // BAD + // attack string: "/" + "\\/a".repeat(100) + // Adapted from ANodeBlog (https://github.com/gefangshuai/ANodeBlog), + // which is licensed under the Apache License 2.0; see file licenses/ANodeBlog-LICENSE. _ = try Regex(#"\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD; attack: "##".repeat(100) + "\na" - // Adapted from CodeMirror (https://github.com/codemirror/codemirror), - // which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE. + // BAD + // attack string: "##".repeat(100) + "\na" + // Adapted from CodeMirror (https://github.com/codemirror/codemirror), + // which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE. _ = try Regex(#"^([\s\[\{\(]|#.*)*$"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD; attack: "a" + "[]".repeat(100) + ".b\n" - // Adapted from Knockout (https://github.com/knockout/knockout), which is - // licensed under the MIT license; see file licenses/knockout-LICENSE + // BAD + // attack string: "a" + "[]".repeat(100) + ".b\n" + // Adapted from Knockout (https://github.com/knockout/knockout), which is + // licensed under the MIT license; see file licenses/knockout-LICENSE _ = try Regex(#"^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD; attack: "[" + "][".repeat(100) + "]!" - // Adapted from Prototype.js (https://github.com/prototypejs/prototype), which - // is licensed under the MIT license; see file licenses/Prototype.js-LICENSE. + // BAD + // attack string: "[" + "][".repeat(100) + "]!" + // Adapted from Prototype.js (https://github.com/prototypejs/prototype), which + // is licensed under the MIT license; see file licenses/Prototype.js-LICENSE. _ = try Regex(#"(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD; attack: "'" + "\\a".repeat(100) + '"' - // Adapted from Prism (https://github.com/PrismJS/prism), which is licensed - // under the MIT license; see file licenses/Prism-LICENSE. + // BAD + // attack string: "'" + "\\a".repeat(100) + '"' + // Adapted from Prism (https://github.com/PrismJS/prism), which is licensed + // under the MIT license; see file licenses/Prism-LICENSE. _ = try Regex(#"("|')(\\?.)*?\1"#).firstMatch(in: tainted) // $ redos-vulnerable= - // more cases: + // more cases: // GOOD _ = try Regex(#"(\r\n|\r|\n)+"#).firstMatch(in: tainted) @@ -114,181 +127,250 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex("(a|.)*").firstMatch(in: tainted) - // Testing the NFA - only some of the below are detected. + // BAD - testing the NFA + // attack string: "a" x lots + "!" _ = try Regex("^([a-z]+)+$").firstMatch(in: tainted) // $ redos-vulnerable= _ = try Regex("^([a-z]*)*$").firstMatch(in: tainted) // $ redos-vulnerable= - _ = try Regex(#"^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^([a-zA-Z0-9])(([\\.-]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$"#).firstMatch(in: tainted) // $ redos-vulnerable= _ = try Regex("^(([a-z])+.)+[A-Z]([a-z])+$").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "b" x lots + "!" _ = try Regex("(b|a?b)*c").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD - _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ redos-vulnerable= - // GOOD _ = try Regex(#"(.|\n)*!"#).firstMatch(in: tainted) - // NOT GOOD; attack: "\n".repeat(100) + "." TODO: investigate, we should be getting this one. + // BAD + // attack string: "\n".repeat(100) + "." + // TODO: investigate, we should be getting this one. _ = try Regex(#"(?s)(.|\n)*!"#).firstMatch(in: tainted) // $ hasParseFailure MISSING: redos-vulnerable= // GOOD _ = try Regex(#"([\w.]+)*"#).firstMatch(in: tainted) + // BAD + // attack string: "a" x lots + "!" + _ = try Regex(#"([\w.]+)*"#).wholeMatch(in: tainted) - // NOT GOOD - _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ redos-vulnerable= - - // NOT GOOD + // BAD + // attack string: "b" x lots + "!" _ = try Regex(#"(([\s\S]|[^a])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - there is no witness in the end that could cause the regexp to not match _ = try Regex(#"([^"']+)*"#).firstMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "b" x lots + "!" _ = try Regex(#"((.|[^a])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"((a|[^a])*)""#).firstMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "b" x lots + "!" _ = try Regex(#"((b|[^a])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "G" x lots + "!" _ = try Regex(#"((G|[^a])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "0" x lots + "!" _ = try Regex(#"(([0-9]|[^a])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD (missing) + // BAD [NOT DETECTED] + // (no confirmed attack string) _ = try Regex(#"(?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"))?"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= - // NOT GOOD (missing) + // BAD [NOT DETECTED] + // (no confirmed attack string) _ = try Regex(#""((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)""#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD _ = try Regex(#""((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*)""#).firstMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "d" x lots + "!" _ = try Regex(#"(([a-z]|[d-h])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "_" x lots _ = try Regex(#"(([^a-z]|[^0-9])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "0" x lots + "!" _ = try Regex(#"((\d|[0-9])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "\n" x lots + "." _ = try Regex(#"((\s|\s)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "G" x lots + "!" _ = try Regex(#"((\w|G)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"((\s|\d)*)""#).firstMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "5" x lots + "!" + _ = try Regex(#"((\d|\d)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= + + // BAD + // attack string: "0" x lots + "!" _ = try Regex(#"((\d|\w)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "5" x lots + "!" _ = try Regex(#"((\d|5)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "\u{000C}" x lots + "!", _ = try Regex(#"((\s|[\f])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD - but not detected (likely because \v is a character class in Java rather than a specific character in other langs) + // BAD + // attack string: "\n" x lots + "." _ = try Regex(#"((\s|[\v]|\\v)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "\u{000C}" x lots + "!", _ = try Regex(#"((\f|[\f])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "\n" x lots + "." _ = try Regex(#"((\W|\D)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "a" x lots + "!" _ = try Regex(#"((\S|\w)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "a" x lots + "!" _ = try Regex(#"((\S|[\w])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "1s" x lots + "!" _ = try Regex(#"((1s|[\da-z])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "0" x lots + "!" _ = try Regex(#"((0|[\d])*)""#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "0" x lots + "!" _ = try Regex(#"(([\d]+)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - there is no witness in the end that could cause the regexp to not match _ = try Regex(#"(\d+(X\d+)?)+"#).firstMatch(in: tainted) + // BAD + // attack string: "0" x lots + "!" + _ = try Regex(#"(\d+(X\d+)?)+"#).wholeMatch(in: tainted) // GOOD - there is no witness in the end that could cause the regexp to not match _ = try Regex("([0-9]+(X[0-9]*)?)*").firstMatch(in: tainted) + // BAD + // attack string: "0" x lots + "!" + _ = try Regex("([0-9]+(X[0-9]*)?)*").wholeMatch(in: tainted) // GOOD _ = try Regex("^([^>]+)*(>|$)").firstMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "##".repeat(100) + "\na" _ = try Regex("^([^>a]+)*(>|$)").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "\n" x lots + "." _ = try Regex(#"(\n\s*)+$"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "\n" x lots + "." _ = try Regex(#"^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|\{\d+(?:,\d*)?})"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // (no confirmed attack string) _ = try Regex(#"\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "a" x lots + "!" _ = try Regex("(a+|b+|c+)*c").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "a" x lots + "!" _ = try Regex("(((a+a?)*)+b+)").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "a" x lots + "!" _ = try Regex("(a+)+bbbb").firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex("(a+)+aaaaa*a+").firstMatch(in: tainted) + // BAD + // attack string: "a" x lots + "!" + _ = try Regex("(a+)+aaaaa*a+").wholeMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "a" x lots + "!" _ = try Regex("(a+)+aaaaa$").firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"(\n+)+\n\n"#).firstMatch(in: tainted) + // BAD + // attack string: "\n" x lots + "." + _ = try Regex(#"(\n+)+\n\n"#).wholeMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "\n" x lots + "." _ = try Regex(#"(\n+)+\n\n$"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: " " x lots + "X" _ = try Regex("([^X]+)*$").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "b" x lots + "!" _ = try Regex("(([^X]b)+)*$").firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex("(([^X]b)+)*($|[^X]b)").firstMatch(in: tainted) + // BAD + // attack string: "b" x lots + "!" + _ = try Regex("(([^X]b)+)*($|[^X]b)").wholeMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "b" x lots + "!" _ = try Regex("(([^X]b)+)*($|[^X]c)").firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex("((ab)+)*ababab").firstMatch(in: tainted) + // BAD + // attack string: "ab" x lots + "!" + _ = try Regex("((ab)+)*ababab").wholeMatch(in: tainted) // GOOD _ = try Regex("((ab)+)*abab(ab)*(ab)+").firstMatch(in: tainted) + // BAD + // attack string: "ab" x lots + "!" + _ = try Regex("((ab)+)*abab(ab)*(ab)+").wholeMatch(in: tainted) // GOOD _ = try Regex("((ab)+)*").firstMatch(in: tainted) + // BAD + // attack string: "ab" x lots + "!" + _ = try Regex("((ab)+)*").wholeMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "ab" x lots + "!" _ = try Regex("((ab)+)*$").firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex("((ab)+)*[a1][b1][a2][b2][a3][b3]").firstMatch(in: tainted) + // BAD + // attack string: "ab" x lots + "!" + _ = try Regex("((ab)+)*[a1][b1][a2][b2][a3][b3]").wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= - // NOT GOOD + // BAD + // (no confirmed attack string) _ = try Regex(#"([\n\s]+)*(.)"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - any witness passes through the accept state. @@ -297,13 +379,16 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex(#"([^\\\]]+)*"#).firstMatch(in: tainted) - // NOT GOOD TODO: QL evaluation times out (for test, at 5 minutes) + // BAD + // TODO: QL evaluation times out (for test, at 5 minutes) // _ = try Regex(#"(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD (but cannot currently construct a prefix) + // BAD (but cannot currently construct a prefix) + // attack string: "aa" + "b" x lots + "!" _ = try Regex("a{2,3}(b+)+X").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD (and a good prefix test) + // BAD (and a good prefix test) + // (no confirmed attack string) _ = try Regex(#"^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD @@ -318,7 +403,8 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex(#"(a+)*([\s\S]*|X)$"#).firstMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "a" x lots + "!" _ = try Regex(#"((a+)*$|[\s\S]+)"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - but still flagged. The only change compared to the above is the order of alternatives, which we don't model. @@ -327,13 +413,16 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex("((;|^)a+)+$").firstMatch(in: tainted) - // NOT GOOD (a good prefix test) + // BAD (a good prefix test) + // attack string: "00000000000000" + "e" x lots + "!" _ = try Regex("(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD - _ = try Regex("^ab(c+)+$").firstMatch(in: tainted) // $ redos-vulnerable= + // BAD + // atack string: "ab" + "c" x lots + "!" + _ = try Regex("^ab(c+)+$").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // (no confirmed attack string) _ = try Regex(#"(\d(\s+)*){20}"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD - but we spuriously conclude that a rejecting suffix exists. @@ -342,43 +431,47 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD - but we spuriously conclude that a rejecting suffix exists. _ = try Regex("^((x([^Y]+)?)*(Y|$))").firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= - // NOT GOOD - _ = try Regex("(a*)+b").firstMatch(in: tainted) // $ redos-vulnerable= - - // NOT GOOD + // BAD + // (no confirmed attack string) _ = try Regex(#"foo([\w-]*)+bar"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "ab" x lots + "!" _ = try Regex("((ab)*)+c").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "a" x lots + "!" _ = try Regex("(a?a?)*b").firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex("(a?)*b").firstMatch(in: tainted) - // NOT GOOD - but not detected + // BAD - but not detected + // (no confirmed attack string) _ = try Regex("(c?a?)*b").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "a" x lots + "!" _ = try Regex("(?:a|a?)+b").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD - but not detected. + // BAD - but not detected. + // attack string: "ab" x lots + "!" _ = try Regex("(a?b?)*$").firstMatch(in: tainted) // $ MISSING: redos-vulnerable= - // NOT GOOD + // BAD + // (no confirmed attack string) _ = try Regex("PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)").firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "a" x lots + "!" _ = try Regex(#"^((a)+\w)+$"#).firstMatch(in: tainted) // $ redos-vulnerable= - // NOT GOOD + // BAD + // attack string: "bbbbbbbbbb." x lots + "!" _ = try Regex("^(b+.)+$").firstMatch(in: tainted) // $ redos-vulnerable= - // GOOD - _ = try Regex("a*b").firstMatch(in: tainted) - - // All 4 bad combinations of nested * and + + // BAD - all 4 bad combinations of nested * and + + // attack string: "a" x lots + "!" _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ redos-vulnerable= _ = try Regex("(a+)*b").firstMatch(in: tainted) // $ redos-vulnerable= _ = try Regex("(a*)+b").firstMatch(in: tainted) // $ redos-vulnerable= @@ -386,9 +479,14 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex("(a|b)+").firstMatch(in: tainted) - _ = try Regex(#"(?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]))+"#).firstMatch(in: tainted) - // TODO: investigate; these were marked `hasParseFailure` + // BAD + _ = try Regex(#"(?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]))+"#).firstMatch(in: tainted) + // BAD + // attack string: ??? + _ = try Regex(#"(?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]))+"#).wholeMatch(in: tainted) + + // TODO: investigate; these were marked `hasParseFailure` _ = try Regex(#"^((?:a{|-)|\w\{)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= _ = try Regex(#"^((?:a{0|-)|\w\{\d)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= _ = try Regex(#"^((?:a{0,|-)|\w\{\d,)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= @@ -397,43 +495,50 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex(#"^((?:a{0,2}|-)|\w\{\d,\d\})+X$"#).firstMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "X" + "a" x lots _ = try Regex(#"X(\u0061|a)*Y"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"X(\u0061|b)+Y"#).firstMatch(in: tainted) - // NOT GOOD TODO: we should get this one + // BAD TODO: we should get this one + // attack string: "X" + "a" x lots _ = try Regex(#"X(\x61|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD _ = try Regex(#"X(\x61|b)+Y"#).firstMatch(in: tainted) - // NOT GOOD TODO: we should get this one + // BAD TODO: we should get this one + // attack string: "X" + "a" x lots _ = try Regex(#"X(\x{061}|a)*Y"#).firstMatch(in: tainted) // $ hasParseFailure= MISSING: redos-vulnerable= // GOOD _ = try Regex(#"X(\x{061}|b)+Y"#).firstMatch(in: tainted) // $ hasParseFailure - // NOT GOOD + // BAD + // attack string: "X" + "7" x lots _ = try Regex(#"X(\p{Digit}|7)*Y"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"X(\p{Digit}|b)+Y"#).firstMatch(in: tainted) - // NOT GOOD + // BAD + // attack string: "X" + "b" x lots _ = try Regex(#"X(\P{Digit}|b)*Y"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"X(\P{Digit}|7)+Y"#).firstMatch(in: tainted) - // NOT GOOD TODO: we should get this one + // BAD TODO: we should get this one + // attack string: "X" + "7" x lots _ = try Regex(#"X(\p{IsDigit}|7)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD _ = try Regex(#"X(\p{IsDigit}|b)+Y"#).firstMatch(in: tainted) - // NOT GOOD - but not detected + // BAD - but not detected + // attack string: "X" + "a" x lots _ = try Regex(#"X(\p{Alpha}|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD @@ -441,12 +546,17 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex(#"("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)"#).firstMatch(in: tainted) + // BAD + // attack string: "##" x lots + "\na" + _ = try Regex(#"("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)"#).wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= // BAD + // attack string: "/" + "\\/a" x lots _ = try Regex(#"/("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X"#).firstMatch(in: tainted) // $ redos-vulnerable= _ = try Regex(#"/("[^"]*?"|[^"\s]+)+(?=X)"#).firstMatch(in: tainted) // $ redos-vulnerable= // BAD + // attack string: "0" x lots + "!" _ = try Regex(#"\A(\d|0)*x"#).firstMatch(in: tainted) // $ redos-vulnerable= _ = try Regex(#"(\d|0)*\Z"#).firstMatch(in: tainted) // $ redos-vulnerable= _ = try Regex(#"\b(\d|0)*x"#).firstMatch(in: tainted) // $ redos-vulnerable= @@ -456,9 +566,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("(a*)*+b").firstMatch(in: tainted) // $ hasParseFailure _ = try Regex("(a*+)*b").firstMatch(in: tainted) // $ hasParseFailure - // BAD - _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ redos-vulnerable= - // BAD - but not detected due to the way possessive quantifiers are approximated + // attack string: "aab" x lots + "!" _ = try Regex("((aa|a*+)b)*c").firstMatch(in: tainted) // $ hasParseFailure MISSING: redos-vulnerable= } diff --git a/swift/ql/test/library-tests/regex/regex.ql b/swift/ql/test/library-tests/regex/regex.ql index 8730b6539ce..3c8579bff84 100644 --- a/swift/ql/test/library-tests/regex/regex.ql +++ b/swift/ql/test/library-tests/regex/regex.ql @@ -44,9 +44,9 @@ module RegexTest implements TestSig { location = eval.getLocation() and element = eval.toString() and tag = "regex" and - value = quote(regex.toString()) + value = quote(regex.toString().replaceAll("\n", "NEWLINE")) ) - } + } } import MakeTest diff --git a/swift/ql/test/library-tests/regex/regex.swift b/swift/ql/test/library-tests/regex/regex.swift index c3dbb6da172..badf568720b 100644 --- a/swift/ql/test/library-tests/regex/regex.swift +++ b/swift/ql/test/library-tests/regex/regex.swift @@ -145,4 +145,10 @@ func myRegexpMethodsTests(b: Bool) throws { let base_str = "a" let append_regex = try Regex(base_str + "b") _ = try append_regex.firstMatch(in: input) // $ input=input MISSING: regex=ab + + // --- escape sequences --- + + _ = try Regex("\n").firstMatch(in: input) // $ regex=NEWLINE input=input + _ = try Regex("\\n").firstMatch(in: input) // $ regex=\n input=input + _ = try Regex(#"\n"#).firstMatch(in: input) // $ regex=\n input=input } diff --git a/swift/ql/test/library-tests/regex/test_the_tests.swift.disabled b/swift/ql/test/library-tests/regex/test_the_tests.swift.disabled new file mode 100644 index 00000000000..00a062a5dca --- /dev/null +++ b/swift/ql/test/library-tests/regex/test_the_tests.swift.disabled @@ -0,0 +1,145 @@ +// This program tests the regular expressions from the tests to (hopefully) figure out which ones +// are really vulnerable to various attack strings in Swift. And confirm they are valid Swift +// regular expressions in the first place. +// +// It works by searching the source file for regular expressions in a particular form +// (roughly `Regex("...")`). A slight catch is that it doesn't process escape characters in the +// way Swift does, so it's best not to use them (use Swift #""# strings to avoid needing them). + +import Foundation + +class TestCase: Thread { + var regex: Regex + var regexStr: String + var targetString: String + var wholeMatch: Bool + var matched: Bool + var done: Bool + + init(regex: Regex, regexStr: String, targetString: String, wholeMatch: Bool) { + self.regex = regex + self.regexStr = regexStr + self.targetString = targetString + self.wholeMatch = wholeMatch + self.matched = false + self.done = false + } + + override func main() { + // run the regex on the target string + do + { + if (wholeMatch) { + if let _ = try regex.wholeMatch(in: targetString) { + matched = true + //print(" wholeMatch \(regexStr) on \(targetString)") + } + } else { + if let _ = try regex.firstMatch(in: targetString) { + matched = true + //print(" firstMatch \(regexStr) on \(targetString)") + } + } + } catch { + print("WEIRD FAILURE") + } + done = true + } +} + +let attackStrings = [ + String(repeating: "a", count: 100) + "!", + String(repeating: "b", count: 100) + "!", + String(repeating: "d", count: 100) + "!", + String(repeating: "G", count: 100) + "!", + String(repeating: "0", count: 100) + "!", + String(repeating: "5", count: 100) + "!", + String(repeating: "ab", count: 100) + "!", + String(repeating: "aab", count: 100) + "!", + String(repeating: "1s", count: 100) + "!", + String(repeating: "\n", count: 100) + ".", + + "_" + String(repeating: "__", count: 100) + "!", + " '" + String(repeating: #"\\\\"#, count: 100), + "/" + String(repeating: "\\/a", count:100), + "/" + String(repeating: "\\\\/a", count:100), + String(repeating: "##", count: 100) + "\na", + "a" + String(repeating: "[]", count: 100) + ".b\n", + "[" + String(repeating: "][", count: 100) + "]!", + "'" + String(repeating: "\\a", count: 100) + "\"", + "'" + String(repeating: "\\\\a", count: 100) + "\"", + String(repeating: "\u{000C}", count: 100) + "!", + "00000000000000" + String(repeating: "e", count: 100) + "!", + "aa" + String(repeating: "b", count: 100) + "!", + "ab" + String(repeating: "c", count: 100) + "!", + String(repeating: " X", count: 100) + "!", + String(repeating: "bbbbbbbbbb.", count: 100) + "!", + + "X" + String(repeating: "a", count: 100), + "X" + String(repeating: "b", count: 100), + "X" + String(repeating: "7", count: 100), +] + +print("testing regular expressions...") +print() + +var tests: [TestCase] = [] + +let lineRegex = try Regex(".*Regex\\(#*\"(.*)\"#*\\).*") // only matches `Regex("...")` + +// read source file, process it line by line... +let wholeFile = try String(contentsOfFile: "redos_variants.swift") +var lines = wholeFile.components(separatedBy: .newlines) + +// filter lines (the whole thing is a lot) +lines = Array(lines[1 ..< 120]) + +var regexpCount = 0 +for line in lines { + + // check if the line matches regex... + if let match = try lineRegex.wholeMatch(in: line) { + if let regexSubstr = match.output[1].substring { + let regexStr = String(regexSubstr) + //print("regex: \(regexStr)") + + // create the regex + if let regex = try? Regex(regexStr) { + // create test cases + for attackString in attackStrings { + tests.append(TestCase(regex: regex, regexStr: regexStr, targetString: attackString, wholeMatch: true)) + tests.append(TestCase(regex: regex, regexStr: regexStr, targetString: attackString, wholeMatch: false)) + } + regexpCount += 1 + } else { + print("FAILED TO PARSE \(regexStr)") + } + } + } +} + +// run the tests (in parallel)... +print("\(regexpCount) regular expression(s)") +print("\(tests.count) test case(s)") +for test in tests { + test.start() +} + +// wait... +Thread.sleep(forTimeInterval: 20.0) + +// report those still running +print("incomplete after 20 seconds:") +for test in tests { + if test.done == false { + var str = test.targetString + str = str.replacingOccurrences(of: "\n", with: "\\n") + if str.count > 35 { + str = str.prefix(15) + " ... " + str.suffix(15) + } + let match = test.wholeMatch ? "wholeMatch" : "firstMatch" + print(" \(test.regexStr) on \(str) (\(match))") + } +} + +print("end.") From 2ae5dae474f821e20b9b036d0a158556d65756ae Mon Sep 17 00:00:00 2001 From: yoff Date: Wed, 14 Jun 2023 20:55:45 +0200 Subject: [PATCH 118/364] Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen --- .../dataflow/new/internal/SummaryTypeTracker.qll | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll index d1a65e1c3e5..9ecc1b5ea1d 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll @@ -16,7 +16,8 @@ signature module Input { // Relating content and filters /** - * Gets a content filter to use for a `WithoutContent[content]` step, or has no result if + * Gets a content filter to use for a `WithoutContent[content]` step, (data is not allowed to be stored in `content`) + * or has no result if * the step should be treated as ordinary flow. * * `WithoutContent` is often used to perform strong updates on individual collection elements, but for @@ -26,7 +27,8 @@ signature module Input { TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content); /** - * Gets a content filter to use for a `WithContent[content]` step, or has no result if + * Gets a content filter to use for a `WithContent[content]` step, (data must be stored in `content`) + * or has no result if * the step cannot be handled by type-tracking. * * `WithContent` is often used to perform strong updates on individual collection elements (or rather @@ -57,10 +59,10 @@ signature module Input { /** Gets a summary component for content `c`. */ SummaryComponent content(TypeTrackerContent contents); - /** Gets a summary component where data is not allowed to be stored in `c`. */ + /** Gets a summary component where data is not allowed to be stored in `contents`. */ SummaryComponent withoutContent(TypeTrackerContent contents); - /** Gets a summary component where data must be stored in `c`. */ + /** Gets a summary component where data must be stored in `contents`. */ SummaryComponent withContent(TypeTrackerContent contents); // Callables From af72509ce6bd61462cde7f3fd1b24b154f8f3bcd Mon Sep 17 00:00:00 2001 From: yoff Date: Wed, 14 Jun 2023 20:57:14 +0200 Subject: [PATCH 119/364] Update python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll Co-authored-by: Rasmus Wriedt Larsen --- .../new/internal/TypeTrackerSpecific.qll | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index 6acc4036c16..48881d37285 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -200,24 +200,18 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { class SummaryComponentStack = FlowSummary::SummaryComponentStack; - SummaryComponentStack singleton(SummaryComponent component) { - result = FlowSummary::SummaryComponentStack::singleton(component) - } + predicate singleton = FlowSummary::SummaryComponentStack::singleton/1; - SummaryComponentStack push(SummaryComponent component, SummaryComponentStack stack) { - result = FlowSummary::SummaryComponentStack::push(component, stack) - } + predicate push = FlowSummary::SummaryComponentStack::push/2; // Relating content to summaries - SummaryComponent content(TypeTrackerContent contents) { - result = FlowSummary::SummaryComponent::content(contents) - } + predicate content = FlowSummary::SummaryComponent::content/1; - SummaryComponent withoutContent(TypeTrackerContent contents) { none() } + predicate withoutContent = FlowSummary::SummaryComponent::withoutContent/1; - SummaryComponent withContent(TypeTrackerContent contents) { none() } + predicate withContent = FlowSummary::SummaryComponent::withContent/1; - SummaryComponent return() { result = FlowSummary::SummaryComponent::return() } + predicate return = FlowSummary::SummaryComponent::return/0; // Relating nodes to summaries Node argumentOf(Node call, SummaryComponent arg) { From 0e713e6fc10f57ce13ab49c8ae5738347527180d Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 14 Jun 2023 21:02:42 +0200 Subject: [PATCH 120/364] ruby/python: more consistent naming of parameters --- .../dataflow/new/internal/SummaryTypeTracker.qll | 2 +- .../typetracking/internal/SummaryTypeTracker.qll | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll index 9ecc1b5ea1d..9c6f841651d 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll @@ -50,7 +50,7 @@ signature module Input { /** * Gets the stack obtained by pushing `head` onto `tail`. */ - SummaryComponentStack push(SummaryComponent component, SummaryComponentStack stack); + SummaryComponentStack push(SummaryComponent head, SummaryComponentStack tail); /** Gets a singleton stack representing a return. */ SummaryComponent return(); diff --git a/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll index d1a65e1c3e5..9c6f841651d 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll @@ -16,7 +16,8 @@ signature module Input { // Relating content and filters /** - * Gets a content filter to use for a `WithoutContent[content]` step, or has no result if + * Gets a content filter to use for a `WithoutContent[content]` step, (data is not allowed to be stored in `content`) + * or has no result if * the step should be treated as ordinary flow. * * `WithoutContent` is often used to perform strong updates on individual collection elements, but for @@ -26,7 +27,8 @@ signature module Input { TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content); /** - * Gets a content filter to use for a `WithContent[content]` step, or has no result if + * Gets a content filter to use for a `WithContent[content]` step, (data must be stored in `content`) + * or has no result if * the step cannot be handled by type-tracking. * * `WithContent` is often used to perform strong updates on individual collection elements (or rather @@ -48,7 +50,7 @@ signature module Input { /** * Gets the stack obtained by pushing `head` onto `tail`. */ - SummaryComponentStack push(SummaryComponent component, SummaryComponentStack stack); + SummaryComponentStack push(SummaryComponent head, SummaryComponentStack tail); /** Gets a singleton stack representing a return. */ SummaryComponent return(); @@ -57,10 +59,10 @@ signature module Input { /** Gets a summary component for content `c`. */ SummaryComponent content(TypeTrackerContent contents); - /** Gets a summary component where data is not allowed to be stored in `c`. */ + /** Gets a summary component where data is not allowed to be stored in `contents`. */ SummaryComponent withoutContent(TypeTrackerContent contents); - /** Gets a summary component where data must be stored in `c`. */ + /** Gets a summary component where data must be stored in `contents`. */ SummaryComponent withContent(TypeTrackerContent contents); // Callables From 6521a51d93e6cf034e8727e281e10191928f8124 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 14 Jun 2023 21:14:50 +0200 Subject: [PATCH 121/364] python: unique strings in tests --- .../dataflow/summaries/TestSummaries.qll | 2 +- .../typetracking-summaries/TestSummaries.qll | 18 +++++++++--------- .../typetracking-summaries/summaries.py | 3 ++- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/python/ql/test/experimental/dataflow/summaries/TestSummaries.qll b/python/ql/test/experimental/dataflow/summaries/TestSummaries.qll index 971a653c469..cdd61420bbb 100644 --- a/python/ql/test/experimental/dataflow/summaries/TestSummaries.qll +++ b/python/ql/test/experimental/dataflow/summaries/TestSummaries.qll @@ -60,7 +60,7 @@ private class SummarizedCallableApplyLambda extends SummarizedCallable { } private class SummarizedCallableReversed extends SummarizedCallable { - SummarizedCallableReversed() { this = "reversed" } + SummarizedCallableReversed() { this = "list_reversed" } override DataFlow::CallCfgNode getACall() { result.getFunction().asCfgNode().(NameNode).getId() = this diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll b/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll index c139308c00e..8d626b332a3 100644 --- a/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll +++ b/python/ql/test/experimental/dataflow/typetracking-summaries/TestSummaries.qll @@ -11,7 +11,7 @@ module RecursionGuard { private import semmle.python.dataflow.new.internal.TypeTrackerSpecific as TT private class RecursionGuard extends SummarizedCallable { - RecursionGuard() { this = "RecursionGuard" } + RecursionGuard() { this = "TypeTrackingSummariesRecursionGuard" } override DataFlow::CallCfgNode getACall() { result.getFunction().asCfgNode().(NameNode).getId() = this and @@ -29,7 +29,7 @@ module RecursionGuard { } private class SummarizedCallableIdentity extends SummarizedCallable { - SummarizedCallableIdentity() { this = "identity" } + SummarizedCallableIdentity() { this = "TTS_identity" } override DataFlow::CallCfgNode getACall() { none() } @@ -48,7 +48,7 @@ private class SummarizedCallableIdentity extends SummarizedCallable { // For lambda flow to work, implement lambdaCall and lambdaCreation private class SummarizedCallableApplyLambda extends SummarizedCallable { - SummarizedCallableApplyLambda() { this = "apply_lambda" } + SummarizedCallableApplyLambda() { this = "TTS_apply_lambda" } override DataFlow::CallCfgNode getACall() { none() } @@ -70,7 +70,7 @@ private class SummarizedCallableApplyLambda extends SummarizedCallable { } private class SummarizedCallableReversed extends SummarizedCallable { - SummarizedCallableReversed() { this = "reversed" } + SummarizedCallableReversed() { this = "TTS_reversed" } override DataFlow::CallCfgNode getACall() { none() } @@ -88,7 +88,7 @@ private class SummarizedCallableReversed extends SummarizedCallable { } private class SummarizedCallableMap extends SummarizedCallable { - SummarizedCallableMap() { this = "list_map" } + SummarizedCallableMap() { this = "TTS_list_map" } override DataFlow::CallCfgNode getACall() { none() } @@ -110,7 +110,7 @@ private class SummarizedCallableMap extends SummarizedCallable { } private class SummarizedCallableAppend extends SummarizedCallable { - SummarizedCallableAppend() { this = "append_to_list" } + SummarizedCallableAppend() { this = "TTS_append_to_list" } override DataFlow::CallCfgNode getACall() { none() } @@ -132,7 +132,7 @@ private class SummarizedCallableAppend extends SummarizedCallable { } private class SummarizedCallableJsonLoads extends SummarizedCallable { - SummarizedCallableJsonLoads() { this = "json.loads" } + SummarizedCallableJsonLoads() { this = "TTS_json.loads" } override DataFlow::CallCfgNode getACall() { result = API::moduleImport("json").getMember("loads").getACall() @@ -153,7 +153,7 @@ private class SummarizedCallableJsonLoads extends SummarizedCallable { // read and store private class SummarizedCallableReadSecret extends SummarizedCallable { - SummarizedCallableReadSecret() { this = "read_secret" } + SummarizedCallableReadSecret() { this = "TTS_read_secret" } override DataFlow::CallCfgNode getACall() { none() } @@ -171,7 +171,7 @@ private class SummarizedCallableReadSecret extends SummarizedCallable { } private class SummarizedCallableSetSecret extends SummarizedCallable { - SummarizedCallableSetSecret() { this = "set_secret" } + SummarizedCallableSetSecret() { this = "TTS_set_secret" } override DataFlow::CallCfgNode getACall() { none() } diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py index 728456cc711..d4195787185 100644 --- a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py +++ b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py @@ -46,6 +46,7 @@ another_tainted_list = append_to_list([], tracked) # $ tracked atl = another_tainted_list[0] atl # $ MISSING: tracked +# This will not work, as the call is not found by `getACallSimple`. from json import loads as json_loads tainted_resultlist = json_loads(tracked) # $ tracked tr = tainted_resultlist[0] @@ -57,4 +58,4 @@ r # $ tracked y # $ tracked=secret set_secret(y, tracked) # $ tracked tracked=secret -y.secret # $ tracked tracked=secret \ No newline at end of file +y.secret # $ tracked tracked=secret From 2491fda58e7a014ed41f383955e8f0b232ba3b17 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 14 Jun 2023 21:16:39 +0200 Subject: [PATCH 122/364] python: update comment --- .../semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index 48881d37285..823e26688da 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -243,7 +243,7 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { Node returnOf(Node callable, SummaryComponent return) { return = FlowSummary::SummaryComponent::return() and - // result should be return value of callable which should be a lambda + // `result` should be the return value of a callable expresion (lambda or function) referenced by `callable` result.asCfgNode() = callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getAReturnValueFlowNode() } From 0267b329040171f11255231f6d36bc1ed257cb62 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 14 Jun 2023 21:17:12 +0200 Subject: [PATCH 123/364] fix eol --- config/identical-files.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/identical-files.json b/config/identical-files.json index 39dadd75ab3..ceed02ba5d6 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -603,4 +603,4 @@ "python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll", "java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll" ] -} \ No newline at end of file +} From 4fded84a49cbc07d69d5c8659a96fb25dc6c07bd Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 14 Jun 2023 21:30:58 +0200 Subject: [PATCH 124/364] python: implement missing predicates --- .../python/dataflow/new/internal/TypeTrackerSpecific.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index 823e26688da..8817cdf21ce 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -207,9 +207,9 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { // Relating content to summaries predicate content = FlowSummary::SummaryComponent::content/1; - predicate withoutContent = FlowSummary::SummaryComponent::withoutContent/1; + SummaryComponent withoutContent(TypeTrackerContent contents) { none() } - predicate withContent = FlowSummary::SummaryComponent::withContent/1; + SummaryComponent withContent(TypeTrackerContent contents) { none() } predicate return = FlowSummary::SummaryComponent::return/0; From b7bf750174f5494776799b63288c9a3cc6ad979b Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 14 Jun 2023 22:23:21 +0200 Subject: [PATCH 125/364] python: use updated names in test --- .../typetracking-summaries/summaries.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py index d4195787185..5801b8e7961 100644 --- a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py +++ b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py @@ -2,25 +2,25 @@ import sys import os # Simple summary -tainted = identity(tracked) # $ tracked +tainted = TTS_identity(tracked) # $ tracked tainted # $ tracked # Lambda summary # I think the missing result is expected because type tracking # is not allowed to flow back out of a call. -tainted_lambda = apply_lambda(lambda x: x, tracked) # $ tracked +tainted_lambda = TTS_apply_lambda(lambda x: x, tracked) # $ tracked tainted_lambda # $ MISSING: tracked # A lambda that directly introduces taint -bad_lambda = apply_lambda(lambda x: tracked, 1) # $ tracked +bad_lambda = TTS_apply_lambda(lambda x: tracked, 1) # $ tracked bad_lambda # $ tracked # A lambda that breaks the flow -untainted_lambda = apply_lambda(lambda x: 1, tracked) # $ tracked +untainted_lambda = TTS_apply_lambda(lambda x: 1, tracked) # $ tracked untainted_lambda # Collection summaries -tainted_list = reversed([tracked]) # $ tracked +tainted_list = TTS_reversed([tracked]) # $ tracked tl = tainted_list[0] tl # $ MISSING: tracked @@ -28,21 +28,21 @@ tl # $ MISSING: tracked def add_colon(x): return x + ":" -tainted_mapped = list_map(add_colon, [tracked]) # $ tracked +tainted_mapped = TTS_list_map(add_colon, [tracked]) # $ tracked tm = tainted_mapped[0] tm # $ MISSING: tracked def explicit_identity(x): return x -tainted_mapped_explicit = list_map(explicit_identity, [tracked]) # $ tracked +tainted_mapped_explicit = TTS_list_map(explicit_identity, [tracked]) # $ tracked tainted_mapped_explicit[0] # $ MISSING: tracked -tainted_mapped_summary = list_map(identity, [tracked]) # $ tracked +tainted_mapped_summary = TTS_list_map(identity, [tracked]) # $ tracked tms = tainted_mapped_summary[0] tms # $ MISSING: tracked -another_tainted_list = append_to_list([], tracked) # $ tracked +another_tainted_list = TTS_append_to_list([], tracked) # $ tracked atl = another_tainted_list[0] atl # $ MISSING: tracked @@ -53,9 +53,9 @@ tr = tainted_resultlist[0] tr # $ MISSING: tracked x.secret = tracked # $ tracked=secret tracked -r = read_secret(x) # $ tracked=secret tracked +r = TTS_read_secret(x) # $ tracked=secret tracked r # $ tracked y # $ tracked=secret -set_secret(y, tracked) # $ tracked tracked=secret +TTS_set_secret(y, tracked) # $ tracked tracked=secret y.secret # $ tracked tracked=secret From eb62df6ece139eaa02241f96c608da9ed0b6d680 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 13 Jun 2023 14:52:32 +0200 Subject: [PATCH 126/364] Go: Rewrite `InlineFlowTest` as a parameterized module --- .../2023-06-14-log-injection-deprecation.md | 4 + go/ql/lib/semmle/go/security/LogInjection.qll | 15 +- go/ql/src/Security/CWE-117/LogInjection.ql | 6 +- go/ql/test/TestUtilities/InlineFlowTest.qll | 128 +++++++++--------- .../ExternalFlow/completetest.expected | 1 + .../go/dataflow/ExternalFlow/completetest.ql | 14 +- .../GenericFunctionsAndTypes/Flows.expected | 2 + .../GenericFunctionsAndTypes/Flows.ql | 1 + .../CWE-117/LogInjectionTest.expected | 2 + .../Security/CWE-117/LogInjectionTest.ql | 9 +- 10 files changed, 95 insertions(+), 87 deletions(-) create mode 100644 go/ql/lib/change-notes/2023-06-14-log-injection-deprecation.md diff --git a/go/ql/lib/change-notes/2023-06-14-log-injection-deprecation.md b/go/ql/lib/change-notes/2023-06-14-log-injection-deprecation.md new file mode 100644 index 00000000000..88ec05c17ce --- /dev/null +++ b/go/ql/lib/change-notes/2023-06-14-log-injection-deprecation.md @@ -0,0 +1,4 @@ +--- +category: deprecated +--- +* The `LogInjection::Configuration` taint flow configuration class has been deprecated. Use the `LogInjection::Flow` module instead. \ No newline at end of file diff --git a/go/ql/lib/semmle/go/security/LogInjection.qll b/go/ql/lib/semmle/go/security/LogInjection.qll index 12f64c87e4a..70e0947c53b 100644 --- a/go/ql/lib/semmle/go/security/LogInjection.qll +++ b/go/ql/lib/semmle/go/security/LogInjection.qll @@ -17,7 +17,7 @@ module LogInjection { /** * A taint-tracking configuration for reasoning about log injection vulnerabilities. */ - class Configuration extends TaintTracking::Configuration { + deprecated class Configuration extends TaintTracking::Configuration { Configuration() { this = "LogInjection" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -30,4 +30,17 @@ module LogInjection { guard instanceof SanitizerGuard } } + + /** + * A taint-tracking configuration for reasoning about log injection vulnerabilities. + */ + module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer } + } + + module Flow = TaintTracking::Global; } diff --git a/go/ql/src/Security/CWE-117/LogInjection.ql b/go/ql/src/Security/CWE-117/LogInjection.ql index 39952dbbfa1..5b6586c8e4e 100644 --- a/go/ql/src/Security/CWE-117/LogInjection.ql +++ b/go/ql/src/Security/CWE-117/LogInjection.ql @@ -13,9 +13,9 @@ import go import semmle.go.security.LogInjection -import DataFlow::PathGraph +import LogInjection::Flow::PathGraph -from LogInjection::Configuration c, DataFlow::PathNode source, DataFlow::PathNode sink -where c.hasFlowPath(source, sink) +from LogInjection::Flow::PathNode source, LogInjection::Flow::PathNode sink +where LogInjection::Flow::flowPath(source, sink) select sink.getNode(), source, sink, "This log entry depends on a $@.", source.getNode(), "user-provided value" diff --git a/go/ql/test/TestUtilities/InlineFlowTest.qll b/go/ql/test/TestUtilities/InlineFlowTest.qll index 0726265699f..f8d54c82f3f 100644 --- a/go/ql/test/TestUtilities/InlineFlowTest.qll +++ b/go/ql/test/TestUtilities/InlineFlowTest.qll @@ -3,37 +3,30 @@ * * Example for a test.ql: * ```ql - * import java + * import go * import TestUtilities.InlineFlowTest + * import DefaultFlowTest * ``` * * To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. - * Example of the corresponding test file, e.g. Test.java + * Example of the corresponding test file, e.g. Test.go * ```go - * public class Test { - * - * Object source() { return null; } - * String taint() { return null; } - * void sink(Object o) { } - * - * public void test() { - * Object s = source(); - * sink(s); //$hasValueFlow - * String t = "foo" + taint(); - * sink(t); //$hasTaintFlow - * } + * func source() string { return ""; } + * func taint() string { return ""; } + * func sink(s string) { } * + * func test() { + * s := source() + * sink(s) // $ hasValueFlow="s" + * t := "foo" + taint() + * sink(t) // $ hasTaintFlow="t" * } * ``` * - * If you're not interested in a specific flow type, you can disable either value or taint flow expectations as follows: - * ```ql - * class HasFlowTest extends InlineFlowTest { - * override DataFlow::Configuration getTaintFlowConfig() { none() } - * - * override DataFlow::Configuration getValueFlowConfig() { none() } - * } - * ``` + * If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import + * `ValueFlowTest`. Similarly, if you are only interested in taint flow, then instead of + * importing `DefaultFlowTest`, you can import `TaintFlowTest`. In both cases + * `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`. * * If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`. */ @@ -47,57 +40,62 @@ private predicate defaultSource(DataFlow::Node source) { ) } -class DefaultValueFlowConf extends DataFlow::Configuration { - DefaultValueFlowConf() { this = "qltest:defaultValueFlowConf" } - - override predicate isSource(DataFlow::Node source) { defaultSource(source) } - - override predicate isSink(DataFlow::Node sink) { - exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument()) - } - - override int fieldFlowBranchLimit() { result = 1000 } +private predicate defaultSink(DataFlow::Node sink) { + exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument()) } -class DefaultTaintFlowConf extends TaintTracking::Configuration { - DefaultTaintFlowConf() { this = "qltest:defaultTaintFlowConf" } +module DefaultFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { defaultSource(source) } - override predicate isSource(DataFlow::Node source) { defaultSource(source) } + predicate isSink(DataFlow::Node sink) { defaultSink(sink) } - override predicate isSink(DataFlow::Node sink) { - exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument()) - } - - override int fieldFlowBranchLimit() { result = 1000 } + int fieldFlowBranchLimit() { result = 1000 } } -class InlineFlowTest extends InlineExpectationsTest { - InlineFlowTest() { this = "HasFlowTest" } +private module NoFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { none() } - override string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] } + predicate isSink(DataFlow::Node sink) { none() } +} - override predicate hasActualResult(Location location, string element, string tag, string value) { - tag = "hasValueFlow" and - exists(DataFlow::Node sink | this.getValueFlowConfig().hasFlowTo(sink) | - sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), - location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and - element = sink.toString() and - value = "\"" + sink.toString() + "\"" - ) - or - tag = "hasTaintFlow" and - exists(DataFlow::Node src, DataFlow::Node sink | - this.getTaintFlowConfig().hasFlow(src, sink) and - not this.getValueFlowConfig().hasFlow(src, sink) - | - sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), - location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and - element = sink.toString() and - value = "\"" + sink.toString() + "\"" - ) +module FlowTest { + module ValueFlow = DataFlow::Global; + + module TaintFlow = TaintTracking::Global; + + private module InlineTest implements TestSig { + string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasValueFlow" and + exists(DataFlow::Node sink | ValueFlow::flowTo(sink) | + sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + element = sink.toString() and + value = "\"" + sink.toString() + "\"" + ) + or + tag = "hasTaintFlow" and + exists(DataFlow::Node src, DataFlow::Node sink | + TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink) + | + sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + element = sink.toString() and + value = "\"" + sink.toString() + "\"" + ) + } } - DataFlow::Configuration getValueFlowConfig() { result = any(DefaultValueFlowConf config) } - - DataFlow::Configuration getTaintFlowConfig() { result = any(DefaultTaintFlowConf config) } + import MakeTest +} + +module DefaultFlowTest = FlowTest; + +module ValueFlowTest { + import FlowTest +} + +module TaintFlowTest { + import FlowTest } diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.expected index 81332464f79..105b7026d0c 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.expected @@ -1,2 +1,3 @@ failures invalidModelRow +testFailures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql index 9719a9d69a6..2b719551ae0 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql @@ -8,16 +8,10 @@ import ModelValidation import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl import TestUtilities.InlineFlowTest -class Config extends TaintTracking::Configuration { - Config() { this = "external-flow-test" } +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node src) { sourceNode(src, "qltest") } - override predicate isSource(DataFlow::Node src) { sourceNode(src, "qltest") } - - override predicate isSink(DataFlow::Node src) { sinkNode(src, "qltest") } + predicate isSink(DataFlow::Node src) { sinkNode(src, "qltest") } } -class ExternalFlowTest extends InlineFlowTest { - override DataFlow::Configuration getValueFlowConfig() { none() } - - override DataFlow::Configuration getTaintFlowConfig() { result = any(Config config) } -} +import TaintFlowTest diff --git a/go/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/Flows.expected b/go/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/Flows.expected index e69de29bb2d..48de9172b36 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/Flows.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/Flows.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/Flows.ql b/go/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/Flows.ql index 881d262f400..1b27b27d6dc 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/Flows.ql +++ b/go/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/Flows.ql @@ -1,2 +1,3 @@ import go import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/go/ql/test/query-tests/Security/CWE-117/LogInjectionTest.expected b/go/ql/test/query-tests/Security/CWE-117/LogInjectionTest.expected index e69de29bb2d..48de9172b36 100644 --- a/go/ql/test/query-tests/Security/CWE-117/LogInjectionTest.expected +++ b/go/ql/test/query-tests/Security/CWE-117/LogInjectionTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/go/ql/test/query-tests/Security/CWE-117/LogInjectionTest.ql b/go/ql/test/query-tests/Security/CWE-117/LogInjectionTest.ql index 576ce9ba342..298287ec4aa 100644 --- a/go/ql/test/query-tests/Security/CWE-117/LogInjectionTest.ql +++ b/go/ql/test/query-tests/Security/CWE-117/LogInjectionTest.ql @@ -1,11 +1,4 @@ import go import TestUtilities.InlineFlowTest import semmle.go.security.LogInjection - -class LogInjectionTest extends InlineFlowTest { - override DataFlow::Configuration getTaintFlowConfig() { - result = any(LogInjection::Configuration config) - } - - override DataFlow::Configuration getValueFlowConfig() { none() } -} +import TaintFlowTest From 853bf2ae4eda2f20aa03df78dae47b0db2a8d658 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 14 Jun 2023 12:04:49 +0200 Subject: [PATCH 127/364] C#: Rewrite `InlineFlowTest` as a parameterized module --- .../ql/test/TestUtilities/InlineFlowTest.qll | 87 +++++++++++-------- .../dataflow/fields/FieldFlow.expected | 1 + .../dataflow/fields/FieldFlow.ql | 7 +- .../dataflow/operators/operatorFlow.expected | 1 + .../dataflow/operators/operatorFlow.ql | 7 +- .../dataflow/patterns/PatternFlow.expected | 1 + .../dataflow/patterns/PatternFlow.ql | 7 +- .../dataflow/tuples/Tuples.expected | 1 + .../library-tests/dataflow/tuples/Tuples.ql | 7 +- 9 files changed, 71 insertions(+), 48 deletions(-) diff --git a/csharp/ql/test/TestUtilities/InlineFlowTest.qll b/csharp/ql/test/TestUtilities/InlineFlowTest.qll index a31d531e1b6..dc95063f03f 100644 --- a/csharp/ql/test/TestUtilities/InlineFlowTest.qll +++ b/csharp/ql/test/TestUtilities/InlineFlowTest.qll @@ -4,11 +4,12 @@ * Example for a test.ql: * ```ql * import csharp - * import DefaultValueFlow::PathGraph * import TestUtilities.InlineFlowTest + * import DefaultFlowTest + * import ValueFlow::PathGraph * - * from DefaultValueFlow::PathNode source, DefaultValueFlow::PathNode sink - * where DefaultValueFlow::flowPath(source, sink) + * from ValueFlow::PathNode source, ValueFlow::PathNode sink + * where ValueFlow::flowPath(source, sink) * select sink, source, sink, "$@", source, source.toString() * * ``` @@ -32,14 +33,10 @@ * } * ``` * - * If you're not interested in a specific flow type, you can disable either value or taint flow expectations as follows: - * ```ql - * class HasFlowTest extends InlineFlowTest { - * override DataFlow::Configuration getTaintFlowConfig() { none() } - * - * override DataFlow::Configuration getValueFlowConfig() { none() } - * } - * ``` + * If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import + * `ValueFlowTest`. Similarly, if you are only interested in taint flow, then instead of + * importing `DefaultFlowTest`, you can import `TaintFlowTest`. In both cases + * `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`. * * If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`. */ @@ -47,8 +44,8 @@ import csharp import TestUtilities.InlineExpectationsTest -private predicate defaultSource(DataFlow::Node src) { - src.asExpr().(MethodCall).getTarget().getUndecoratedName() = ["Source", "Taint"] +private predicate defaultSource(DataFlow::Node source) { + source.asExpr().(MethodCall).getTarget().getUndecoratedName() = ["Source", "Taint"] } private predicate defaultSink(DataFlow::Node sink) { @@ -58,42 +55,60 @@ private predicate defaultSink(DataFlow::Node sink) { } module DefaultFlowConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node n) { defaultSource(n) } + predicate isSource(DataFlow::Node source) { defaultSource(source) } - predicate isSink(DataFlow::Node n) { defaultSink(n) } + predicate isSink(DataFlow::Node sink) { defaultSink(sink) } int fieldFlowBranchLimit() { result = 1000 } } -module DefaultValueFlow = DataFlow::Global; +private module NoFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { none() } -module DefaultTaintFlow = TaintTracking::Global; + predicate isSink(DataFlow::Node sink) { none() } +} private string getSourceArgString(DataFlow::Node src) { defaultSource(src) and src.asExpr().(MethodCall).getAnArgument().getValue() = result } -class InlineFlowTest extends InlineExpectationsTest { - InlineFlowTest() { this = "HasFlowTest" } +module FlowTest { + module ValueFlow = DataFlow::Global; - override string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] } + module TaintFlow = TaintTracking::Global; - override predicate hasActualResult(Location location, string element, string tag, string value) { - tag = "hasValueFlow" and - exists(DataFlow::Node src, DataFlow::Node sink | DefaultValueFlow::flow(src, sink) | - sink.getLocation() = location and - element = sink.toString() and - if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" - ) - or - tag = "hasTaintFlow" and - exists(DataFlow::Node src, DataFlow::Node sink | - DefaultTaintFlow::flow(src, sink) and not DefaultValueFlow::flow(src, sink) - | - sink.getLocation() = location and - element = sink.toString() and - if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" - ) + private module InlineTest implements TestSig { + string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasValueFlow" and + exists(DataFlow::Node src, DataFlow::Node sink | ValueFlow::flow(src, sink) | + sink.getLocation() = location and + element = sink.toString() and + if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" + ) + or + tag = "hasTaintFlow" and + exists(DataFlow::Node src, DataFlow::Node sink | + TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink) + | + sink.getLocation() = location and + element = sink.toString() and + if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" + ) + } } + + import MakeTest +} + +module DefaultFlowTest = FlowTest; + +module ValueFlowTest { + import FlowTest +} + +module TaintFlowTest { + import FlowTest } diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index aa9ac0493aa..a0d9a917702 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -1,4 +1,5 @@ failures +testFailures edges | A.cs:5:17:5:28 | call to method Source : C | A.cs:6:24:6:24 | access to local variable c : C | | A.cs:6:17:6:25 | call to method Make : B [field c] : C | A.cs:7:14:7:14 | access to local variable b : B [field c] : C | diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.ql b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.ql index b01c0f7fcaf..39395ad831b 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.ql @@ -3,9 +3,10 @@ */ import csharp -import DefaultValueFlow::PathGraph import TestUtilities.InlineFlowTest +import DefaultFlowTest +import ValueFlow::PathGraph -from DefaultValueFlow::PathNode source, DefaultValueFlow::PathNode sink -where DefaultValueFlow::flowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected index 7b173a98e41..3f4f02ff6a1 100644 --- a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected @@ -1,4 +1,5 @@ failures +testFailures edges | Operator.cs:9:39:9:39 | x : C | Operator.cs:9:50:9:50 | access to parameter x : C | | Operator.cs:16:38:16:38 | x : C | Operator.cs:16:49:16:49 | access to parameter x : C | diff --git a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.ql b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.ql index b01c0f7fcaf..39395ad831b 100644 --- a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.ql @@ -3,9 +3,10 @@ */ import csharp -import DefaultValueFlow::PathGraph import TestUtilities.InlineFlowTest +import DefaultFlowTest +import ValueFlow::PathGraph -from DefaultValueFlow::PathNode source, DefaultValueFlow::PathNode sink -where DefaultValueFlow::flowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected index f965891244c..f2ab31c12b3 100644 --- a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected @@ -1,4 +1,5 @@ failures +testFailures edges nodes subpaths diff --git a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.ql b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.ql index b01c0f7fcaf..39395ad831b 100644 --- a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.ql @@ -3,9 +3,10 @@ */ import csharp -import DefaultValueFlow::PathGraph import TestUtilities.InlineFlowTest +import DefaultFlowTest +import ValueFlow::PathGraph -from DefaultValueFlow::PathNode source, DefaultValueFlow::PathNode sink -where DefaultValueFlow::flowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected index dae85aa45aa..bb1715df029 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected @@ -1,4 +1,5 @@ failures +testFailures edges | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:10:21:10:22 | access to local variable o1 : Object | | Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:10:29:10:30 | access to local variable o2 : Object | diff --git a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.ql b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.ql index b01c0f7fcaf..39395ad831b 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.ql +++ b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.ql @@ -3,9 +3,10 @@ */ import csharp -import DefaultValueFlow::PathGraph import TestUtilities.InlineFlowTest +import DefaultFlowTest +import ValueFlow::PathGraph -from DefaultValueFlow::PathNode source, DefaultValueFlow::PathNode sink -where DefaultValueFlow::flowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() From 742eb8dd12c1b07cc112ff26a9caaa9c472ba23b Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 14 Jun 2023 13:42:13 +0200 Subject: [PATCH 128/364] Java: Rewrite `InlineFlowTest` as a parameterized module --- .../flowtestcasegenerator/testHeader.qlfrag | 1 + java/ql/test/TestUtilities/InlineFlowTest.qll | 97 ++++++++++--------- java/ql/test/ext/TestModels/test.expected | 2 + java/ql/test/ext/TestModels/test.ql | 1 + .../dataflow/summaries/test.expected | 2 + .../library-tests/dataflow/summaries/test.ql | 1 + .../dataflow/callctx/test.expected | 2 + .../library-tests/dataflow/callctx/test.ql | 1 + .../collections/containerflow.expected | 2 + .../dataflow/collections/containerflow.ql | 1 + .../dataflow/fluent-methods/flow.expected | 2 + .../dataflow/fluent-methods/flow.ql | 1 + .../dataflow/stream-collect/test.expected | 2 + .../dataflow/stream-collect/test.ql | 1 + .../dataflow/synth-global/test.expected | 1 + .../dataflow/synth-global/test.ql | 1 + .../dataflow/taint-format/test.expected | 2 + .../dataflow/taint-format/test.ql | 1 + .../dataflow/taint-gson/dataFlow.expected | 2 + .../dataflow/taint-gson/dataFlow.ql | 1 + .../dataflow/taint-jackson/dataFlow.expected | 2 + .../dataflow/taint-jackson/dataFlow.ql | 1 + .../frameworks/JaxWs/JaxRsFlow.expected | 2 + .../frameworks/JaxWs/JaxRsFlow.ql | 14 +-- .../android/asynctask/test.expected | 2 + .../frameworks/android/asynctask/test.ql | 1 + .../content-provider-summaries/test.expected | 2 + .../content-provider-summaries/test.ql | 1 + .../android/content-provider/test.expected | 2 + .../android/content-provider/test.ql | 10 +- .../android/external-storage/test.expected | 2 + .../android/external-storage/test.ql | 8 +- .../android/flow-steps/test.expected | 2 + .../frameworks/android/flow-steps/test.ql | 1 + .../frameworks/android/intent/test.expected | 2 + .../frameworks/android/intent/test.ql | 1 + .../android/notification/test.expected | 2 + .../frameworks/android/notification/test.ql | 1 + .../frameworks/android/slice/test.expected | 2 + .../frameworks/android/slice/test.ql | 14 +-- .../OnActivityResultSourceTest.expected | 2 + .../sources/OnActivityResultSourceTest.ql | 10 +- .../frameworks/android/uri/test.expected | 2 + .../frameworks/android/uri/test.ql | 1 + .../frameworks/android/widget/test.expected | 1 + .../frameworks/android/widget/test.ql | 1 + .../frameworks/apache-ant/test.expected | 2 + .../frameworks/apache-ant/test.ql | 1 + .../apache-collections/test.expected | 2 + .../frameworks/apache-collections/test.ql | 1 + .../apache-commons-compress/test.expected | 2 + .../apache-commons-compress/test.ql | 1 + .../apache-commons-lang3/flow.expected | 2 + .../frameworks/apache-commons-lang3/flow.ql | 1 + .../frameworks/apache-http/flow.expected | 2 + .../frameworks/apache-http/flow.ql | 8 +- .../frameworks/gson/test.expected | 2 + .../library-tests/frameworks/gson/test.ql | 1 + .../guava/generated/cache/test.expected | 2 + .../frameworks/guava/generated/cache/test.ql | 1 + .../guava/generated/collect/test.expected | 2 + .../guava/generated/collect/test.ql | 1 + .../frameworks/hudson/test.expected | 2 + .../library-tests/frameworks/hudson/test.ql | 1 + .../frameworks/jackson/test.expected | 2 + .../library-tests/frameworks/jackson/test.ql | 1 + .../frameworks/javax-json/test.expected | 2 + .../frameworks/javax-json/test.ql | 1 + .../frameworks/jdk/java.io/test.expected | 2 + .../frameworks/jdk/java.io/test.ql | 1 + .../frameworks/jdk/java.net/test.expected | 2 + .../frameworks/jdk/java.net/test.ql | 1 + .../jdk/java.nio.file/test.expected | 2 + .../frameworks/jdk/java.nio.file/test.ql | 1 + .../frameworks/json-java/test.expected | 2 + .../frameworks/json-java/test.ql | 1 + .../frameworks/netty/generated/test.expected | 2 + .../frameworks/netty/generated/test.ql | 1 + .../frameworks/netty/manual/test.expected | 2 + .../frameworks/netty/manual/test.ql | 8 +- .../frameworks/okhttp/test.expected | 2 + .../library-tests/frameworks/okhttp/test.ql | 8 +- .../frameworks/play/test.expected | 2 + .../library-tests/frameworks/play/test.ql | 1 + .../frameworks/rabbitmq/FlowTest.expected | 2 + .../frameworks/rabbitmq/FlowTest.ql | 8 +- .../frameworks/ratpack/flow.expected | 2 + .../library-tests/frameworks/ratpack/flow.ql | 10 +- .../frameworks/retrofit/test.expected | 2 + .../library-tests/frameworks/retrofit/test.ql | 6 +- .../frameworks/spring/beans/test.expected | 2 + .../frameworks/spring/beans/test.ql | 1 + .../frameworks/spring/cache/test.expected | 2 + .../frameworks/spring/cache/test.ql | 1 + .../frameworks/spring/context/flow.expected | 2 + .../frameworks/spring/context/flow.ql | 1 + .../spring/controller/test.expected | 2 + .../frameworks/spring/controller/test.ql | 8 +- .../frameworks/spring/data/test.expected | 2 + .../frameworks/spring/data/test.ql | 1 + .../frameworks/spring/http/flow.expected | 2 + .../frameworks/spring/http/flow.ql | 1 + .../frameworks/spring/ui/test.expected | 2 + .../frameworks/spring/ui/test.ql | 1 + .../frameworks/spring/util/test.expected | 2 + .../frameworks/spring/util/test.ql | 1 + .../spring/validation/test.expected | 2 + .../frameworks/spring/validation/test.ql | 1 + .../spring/webmultipart/test.expected | 2 + .../frameworks/spring/webmultipart/test.ql | 1 + .../frameworks/spring/webutil/test.expected | 2 + .../frameworks/spring/webutil/test.ql | 1 + .../frameworks/stapler/test.expected | 2 + .../library-tests/frameworks/stapler/test.ql | 1 + .../frameworks/stream/test.expected | 2 + .../library-tests/frameworks/stream/test.ql | 1 + .../frameworks/thymeleaf/test.expected | 2 + .../frameworks/thymeleaf/test.ql | 1 + .../test/library-tests/logging/test.expected | 2 + java/ql/test/library-tests/logging/test.ql | 1 + .../test/library-tests/optional/test.expected | 2 + java/ql/test/library-tests/optional/test.ql | 1 + .../ql/test/library-tests/paths/test.expected | 2 + java/ql/test/library-tests/paths/test.ql | 1 + .../library-tests/pathsanitizer/test.expected | 2 + .../test/library-tests/pathsanitizer/test.ql | 10 +- .../ql/test/library-tests/regex/test.expected | 2 + java/ql/test/library-tests/regex/test.ql | 1 + .../test/library-tests/scanner/test.expected | 2 + java/ql/test/library-tests/scanner/test.ql | 1 + .../CWE-117/LogInjectionTest.expected | 2 + .../security/CWE-117/LogInjectionTest.ql | 8 +- ...tentUriPermissionManipulationTest.expected | 2 + .../IntentUriPermissionManipulationTest.ql | 9 +- .../UnsafeContentUriResolutionTest.expected | 2 + .../CWE-441/UnsafeContentUriResolutionTest.ql | 9 +- .../CWE-470/FragmentInjectionTest.expected | 2 + .../security/CWE-470/FragmentInjectionTest.ql | 9 +- .../WebviewDebuggingEnabled.expected | 2 + .../WebviewDebuggingEnabled.ql | 9 +- .../CWE-532/SensitiveLogInfo.expected | 2 + .../security/CWE-532/SensitiveLogInfo.ql | 9 +- .../query-tests/security/CWE-611/XXE.expected | 2 + .../test/query-tests/security/CWE-611/XXE.ql | 9 +- .../CWE-780/RsaWithoutOaepTest.expected | 2 + .../security/CWE-780/RsaWithoutOaepTest.ql | 9 +- .../CWE-927/SensitiveCommunication.expected | 2 + .../CWE-927/SensitiveCommunication.ql | 9 +- 148 files changed, 271 insertions(+), 224 deletions(-) diff --git a/java/ql/src/utils/flowtestcasegenerator/testHeader.qlfrag b/java/ql/src/utils/flowtestcasegenerator/testHeader.qlfrag index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/src/utils/flowtestcasegenerator/testHeader.qlfrag +++ b/java/ql/src/utils/flowtestcasegenerator/testHeader.qlfrag @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/TestUtilities/InlineFlowTest.qll b/java/ql/test/TestUtilities/InlineFlowTest.qll index 5e37770a279..6f344c5074e 100644 --- a/java/ql/test/TestUtilities/InlineFlowTest.qll +++ b/java/ql/test/TestUtilities/InlineFlowTest.qll @@ -5,6 +5,7 @@ * ```ql * import java * import TestUtilities.InlineFlowTest + * import DefaultFlowTest * ``` * * To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. @@ -18,22 +19,18 @@ * * public void test() { * Object s = source(); - * sink(s); //$hasValueFlow + * sink(s); // $ hasValueFlow * String t = "foo" + taint(); - * sink(t); //$hasTaintFlow + * sink(t); // $ hasTaintFlow * } * * } * ``` * - * If you're not interested in a specific flow type, you can disable either value or taint flow expectations as follows: - * ```ql - * class HasFlowTest extends InlineFlowTest { - * override DataFlow::Configuration getTaintFlowConfig() { none() } - * - * override DataFlow::Configuration getValueFlowConfig() { none() } - * } - * ``` + * If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import + * `ValueFlowTest`. Similarly, if you are only interested in taint flow, then instead of + * importing `DefaultFlowTest`, you can import `TaintFlowTest`. In both cases + * `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`. * * If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`. */ @@ -43,57 +40,69 @@ import semmle.code.java.dataflow.ExternalFlow import semmle.code.java.dataflow.TaintTracking import TestUtilities.InlineExpectationsTest -private predicate defaultSource(DataFlow::Node src) { - src.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"] +private predicate defaultSource(DataFlow::Node source) { + source.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"] +} + +private predicate defaultSink(DataFlow::Node sink) { + exists(MethodAccess ma | ma.getMethod().hasName("sink") | sink.asExpr() = ma.getAnArgument()) } module DefaultFlowConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node n) { defaultSource(n) } + predicate isSource(DataFlow::Node source) { defaultSource(source) } - predicate isSink(DataFlow::Node n) { - exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument()) - } + predicate isSink(DataFlow::Node sink) { defaultSink(sink) } int fieldFlowBranchLimit() { result = 1000 } } -private module DefaultValueFlow = DataFlow::Global; +private module NoFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { none() } -private module DefaultTaintFlow = TaintTracking::Global; + predicate isSink(DataFlow::Node sink) { none() } +} private string getSourceArgString(DataFlow::Node src) { defaultSource(src) and src.asExpr().(MethodAccess).getAnArgument().(StringLiteral).getValue() = result } -class InlineFlowTest extends InlineExpectationsTest { - InlineFlowTest() { this = "HasFlowTest" } +module FlowTest { + module ValueFlow = DataFlow::Global; - override string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] } + module TaintFlow = TaintTracking::Global; - override predicate hasActualResult(Location location, string element, string tag, string value) { - tag = "hasValueFlow" and - exists(DataFlow::Node src, DataFlow::Node sink | this.hasValueFlow(src, sink) | - sink.getLocation() = location and - element = sink.toString() and - if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" - ) - or - tag = "hasTaintFlow" and - exists(DataFlow::Node src, DataFlow::Node sink | - this.hasTaintFlow(src, sink) and not this.hasValueFlow(src, sink) - | - sink.getLocation() = location and - element = sink.toString() and - if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" - ) + private module InlineTest implements TestSig { + string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasValueFlow" and + exists(DataFlow::Node src, DataFlow::Node sink | ValueFlow::flow(src, sink) | + sink.getLocation() = location and + element = sink.toString() and + if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" + ) + or + tag = "hasTaintFlow" and + exists(DataFlow::Node src, DataFlow::Node sink | + TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink) + | + sink.getLocation() = location and + element = sink.toString() and + if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" + ) + } } - predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { - DefaultValueFlow::flow(src, sink) - } - - predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - DefaultTaintFlow::flow(src, sink) - } + import MakeTest +} + +module DefaultFlowTest = FlowTest; + +module ValueFlowTest { + import FlowTest +} + +module TaintFlowTest { + import FlowTest } diff --git a/java/ql/test/ext/TestModels/test.expected b/java/ql/test/ext/TestModels/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/ext/TestModels/test.expected +++ b/java/ql/test/ext/TestModels/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/ext/TestModels/test.ql b/java/ql/test/ext/TestModels/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/ext/TestModels/test.ql +++ b/java/ql/test/ext/TestModels/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/kotlin/library-tests/dataflow/summaries/test.expected b/java/ql/test/kotlin/library-tests/dataflow/summaries/test.expected index f566914ba89..f72956fded3 100644 --- a/java/ql/test/kotlin/library-tests/dataflow/summaries/test.expected +++ b/java/ql/test/kotlin/library-tests/dataflow/summaries/test.expected @@ -1,3 +1,5 @@ +failures +testFailures | test.kt:28:14:28:21 | getSecond(...) | Unexpected result: hasTaintFlow=a | | test.kt:35:14:35:27 | component1(...) | Unexpected result: hasTaintFlow=d | | test.kt:41:14:41:22 | getSecond(...) | Unexpected result: hasTaintFlow=e | diff --git a/java/ql/test/kotlin/library-tests/dataflow/summaries/test.ql b/java/ql/test/kotlin/library-tests/dataflow/summaries/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/kotlin/library-tests/dataflow/summaries/test.ql +++ b/java/ql/test/kotlin/library-tests/dataflow/summaries/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/dataflow/callctx/test.expected b/java/ql/test/library-tests/dataflow/callctx/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/dataflow/callctx/test.expected +++ b/java/ql/test/library-tests/dataflow/callctx/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/dataflow/callctx/test.ql b/java/ql/test/library-tests/dataflow/callctx/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/dataflow/callctx/test.ql +++ b/java/ql/test/library-tests/dataflow/callctx/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/dataflow/collections/containerflow.expected b/java/ql/test/library-tests/dataflow/collections/containerflow.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/dataflow/collections/containerflow.expected +++ b/java/ql/test/library-tests/dataflow/collections/containerflow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/dataflow/collections/containerflow.ql b/java/ql/test/library-tests/dataflow/collections/containerflow.ql index 992971d6dc7..4b1a19535ea 100644 --- a/java/ql/test/library-tests/dataflow/collections/containerflow.ql +++ b/java/ql/test/library-tests/dataflow/collections/containerflow.ql @@ -1,3 +1,4 @@ import java import semmle.code.java.dataflow.DataFlow import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/dataflow/fluent-methods/flow.expected b/java/ql/test/library-tests/dataflow/fluent-methods/flow.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/dataflow/fluent-methods/flow.expected +++ b/java/ql/test/library-tests/dataflow/fluent-methods/flow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql b/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql index 4a9794ab351..944abac0642 100644 --- a/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql +++ b/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql @@ -2,6 +2,7 @@ import java import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.FlowSteps import TestUtilities.InlineFlowTest +import DefaultFlowTest class Model extends FluentMethod { Model() { this.getName() = "modelledFluentMethod" } diff --git a/java/ql/test/library-tests/dataflow/stream-collect/test.expected b/java/ql/test/library-tests/dataflow/stream-collect/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/dataflow/stream-collect/test.expected +++ b/java/ql/test/library-tests/dataflow/stream-collect/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/dataflow/stream-collect/test.ql b/java/ql/test/library-tests/dataflow/stream-collect/test.ql index c4b63c87071..50e3f8d2f7d 100644 --- a/java/ql/test/library-tests/dataflow/stream-collect/test.ql +++ b/java/ql/test/library-tests/dataflow/stream-collect/test.ql @@ -1 +1,2 @@ import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/dataflow/synth-global/test.expected b/java/ql/test/library-tests/dataflow/synth-global/test.expected index 81332464f79..ae4c33edb3d 100644 --- a/java/ql/test/library-tests/dataflow/synth-global/test.expected +++ b/java/ql/test/library-tests/dataflow/synth-global/test.expected @@ -1,2 +1,3 @@ failures +testFailures invalidModelRow diff --git a/java/ql/test/library-tests/dataflow/synth-global/test.ql b/java/ql/test/library-tests/dataflow/synth-global/test.ql index 0d9f2265afc..53f8aa6a6f6 100644 --- a/java/ql/test/library-tests/dataflow/synth-global/test.ql +++ b/java/ql/test/library-tests/dataflow/synth-global/test.ql @@ -1,3 +1,4 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest import ModelValidation diff --git a/java/ql/test/library-tests/dataflow/taint-format/test.expected b/java/ql/test/library-tests/dataflow/taint-format/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/dataflow/taint-format/test.expected +++ b/java/ql/test/library-tests/dataflow/taint-format/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/dataflow/taint-format/test.ql b/java/ql/test/library-tests/dataflow/taint-format/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/dataflow/taint-format/test.ql +++ b/java/ql/test/library-tests/dataflow/taint-format/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/dataflow/taint-gson/dataFlow.expected b/java/ql/test/library-tests/dataflow/taint-gson/dataFlow.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/dataflow/taint-gson/dataFlow.expected +++ b/java/ql/test/library-tests/dataflow/taint-gson/dataFlow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/dataflow/taint-gson/dataFlow.ql b/java/ql/test/library-tests/dataflow/taint-gson/dataFlow.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/dataflow/taint-gson/dataFlow.ql +++ b/java/ql/test/library-tests/dataflow/taint-gson/dataFlow.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.expected b/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.expected +++ b/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.ql b/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.ql +++ b/java/ql/test/library-tests/dataflow/taint-jackson/dataFlow.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.expected b/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.expected +++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.ql b/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.ql index d0ab4274b12..93ab3fe066d 100644 --- a/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.ql +++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.ql @@ -13,16 +13,4 @@ module Config implements DataFlow::ConfigSig { predicate isSink = DefaultFlowConfig::isSink/1; } -module TaintFlow = TaintTracking::Global; - -module ValueFlow = DataFlow::Global; - -class Test extends InlineFlowTest { - override predicate hasTaintFlow(DataFlow::Node source, DataFlow::Node sink) { - TaintFlow::flow(source, sink) - } - - override predicate hasValueFlow(DataFlow::Node source, DataFlow::Node sink) { - ValueFlow::flow(source, sink) - } -} +import FlowTest diff --git a/java/ql/test/library-tests/frameworks/android/asynctask/test.expected b/java/ql/test/library-tests/frameworks/android/asynctask/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/android/asynctask/test.expected +++ b/java/ql/test/library-tests/frameworks/android/asynctask/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/android/asynctask/test.ql b/java/ql/test/library-tests/frameworks/android/asynctask/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/android/asynctask/test.ql +++ b/java/ql/test/library-tests/frameworks/android/asynctask/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/android/content-provider-summaries/test.expected b/java/ql/test/library-tests/frameworks/android/content-provider-summaries/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/android/content-provider-summaries/test.expected +++ b/java/ql/test/library-tests/frameworks/android/content-provider-summaries/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/android/content-provider-summaries/test.ql b/java/ql/test/library-tests/frameworks/android/content-provider-summaries/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/android/content-provider-summaries/test.ql +++ b/java/ql/test/library-tests/frameworks/android/content-provider-summaries/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/android/content-provider/test.expected b/java/ql/test/library-tests/frameworks/android/content-provider/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/android/content-provider/test.expected +++ b/java/ql/test/library-tests/frameworks/android/content-provider/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/android/content-provider/test.ql b/java/ql/test/library-tests/frameworks/android/content-provider/test.ql index f068b30b0d5..2c6bd09dc40 100644 --- a/java/ql/test/library-tests/frameworks/android/content-provider/test.ql +++ b/java/ql/test/library-tests/frameworks/android/content-provider/test.ql @@ -10,12 +10,4 @@ module ProviderTaintFlowConfig implements DataFlow::ConfigSig { int fieldFlowBranchLimit() { result = DefaultFlowConfig::fieldFlowBranchLimit() } } -module ProviderTaintFlow = TaintTracking::Global; - -class ProviderInlineFlowTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - ProviderTaintFlow::flow(src, sink) - } -} +import TaintFlowTest diff --git a/java/ql/test/library-tests/frameworks/android/external-storage/test.expected b/java/ql/test/library-tests/frameworks/android/external-storage/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/android/external-storage/test.expected +++ b/java/ql/test/library-tests/frameworks/android/external-storage/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/android/external-storage/test.ql b/java/ql/test/library-tests/frameworks/android/external-storage/test.ql index c73c0a5c6c9..64ff27077df 100644 --- a/java/ql/test/library-tests/frameworks/android/external-storage/test.ql +++ b/java/ql/test/library-tests/frameworks/android/external-storage/test.ql @@ -11,10 +11,4 @@ module Config implements DataFlow::ConfigSig { } } -module Flow = TaintTracking::Global; - -class ExternalStorageTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { Flow::flow(src, sink) } -} +import TaintFlowTest diff --git a/java/ql/test/library-tests/frameworks/android/flow-steps/test.expected b/java/ql/test/library-tests/frameworks/android/flow-steps/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/android/flow-steps/test.expected +++ b/java/ql/test/library-tests/frameworks/android/flow-steps/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/android/flow-steps/test.ql b/java/ql/test/library-tests/frameworks/android/flow-steps/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/android/flow-steps/test.ql +++ b/java/ql/test/library-tests/frameworks/android/flow-steps/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/android/intent/test.expected b/java/ql/test/library-tests/frameworks/android/intent/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/android/intent/test.expected +++ b/java/ql/test/library-tests/frameworks/android/intent/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/android/intent/test.ql b/java/ql/test/library-tests/frameworks/android/intent/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/android/intent/test.ql +++ b/java/ql/test/library-tests/frameworks/android/intent/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/android/notification/test.expected b/java/ql/test/library-tests/frameworks/android/notification/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/android/notification/test.expected +++ b/java/ql/test/library-tests/frameworks/android/notification/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/android/notification/test.ql b/java/ql/test/library-tests/frameworks/android/notification/test.ql index f0a60550d4d..07c022b1265 100644 --- a/java/ql/test/library-tests/frameworks/android/notification/test.ql +++ b/java/ql/test/library-tests/frameworks/android/notification/test.ql @@ -1,3 +1,4 @@ import java import semmle.code.java.frameworks.android.Intent import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/android/slice/test.expected b/java/ql/test/library-tests/frameworks/android/slice/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/android/slice/test.expected +++ b/java/ql/test/library-tests/frameworks/android/slice/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/android/slice/test.ql b/java/ql/test/library-tests/frameworks/android/slice/test.ql index b3c5fe78094..787f93df5a0 100644 --- a/java/ql/test/library-tests/frameworks/android/slice/test.ql +++ b/java/ql/test/library-tests/frameworks/android/slice/test.ql @@ -11,8 +11,6 @@ module SliceValueFlowConfig implements DataFlow::ConfigSig { predicate isSink = DefaultFlowConfig::isSink/1; } -module SliceValueFlow = DataFlow::Global; - module SliceTaintFlowConfig implements DataFlow::ConfigSig { predicate isSource = DefaultFlowConfig::isSource/1; @@ -24,14 +22,4 @@ module SliceTaintFlowConfig implements DataFlow::ConfigSig { } } -module SliceTaintFlow = TaintTracking::Global; - -class SliceFlowTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node source, DataFlow::Node sink) { - SliceValueFlow::flow(source, sink) - } - - override predicate hasTaintFlow(DataFlow::Node source, DataFlow::Node sink) { - SliceTaintFlow::flow(source, sink) - } -} +import FlowTest diff --git a/java/ql/test/library-tests/frameworks/android/sources/OnActivityResultSourceTest.expected b/java/ql/test/library-tests/frameworks/android/sources/OnActivityResultSourceTest.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/android/sources/OnActivityResultSourceTest.expected +++ b/java/ql/test/library-tests/frameworks/android/sources/OnActivityResultSourceTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/android/sources/OnActivityResultSourceTest.ql b/java/ql/test/library-tests/frameworks/android/sources/OnActivityResultSourceTest.ql index 64c0f48ffa6..5b163a81935 100644 --- a/java/ql/test/library-tests/frameworks/android/sources/OnActivityResultSourceTest.ql +++ b/java/ql/test/library-tests/frameworks/android/sources/OnActivityResultSourceTest.ql @@ -10,12 +10,4 @@ module SourceValueFlowConfig implements DataFlow::ConfigSig { int fieldFlowBranchLimit() { result = DefaultFlowConfig::fieldFlowBranchLimit() } } -module SourceValueFlow = DataFlow::Global; - -class SourceInlineFlowTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { - SourceValueFlow::flow(src, sink) - } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { none() } -} +import ValueFlowTest diff --git a/java/ql/test/library-tests/frameworks/android/uri/test.expected b/java/ql/test/library-tests/frameworks/android/uri/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/android/uri/test.expected +++ b/java/ql/test/library-tests/frameworks/android/uri/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/android/uri/test.ql b/java/ql/test/library-tests/frameworks/android/uri/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/android/uri/test.ql +++ b/java/ql/test/library-tests/frameworks/android/uri/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/android/widget/test.expected b/java/ql/test/library-tests/frameworks/android/widget/test.expected index 8329ef6b41b..5390495c737 100644 --- a/java/ql/test/library-tests/frameworks/android/widget/test.expected +++ b/java/ql/test/library-tests/frameworks/android/widget/test.expected @@ -1,2 +1,3 @@ failures +testFailures valueOf diff --git a/java/ql/test/library-tests/frameworks/android/widget/test.ql b/java/ql/test/library-tests/frameworks/android/widget/test.ql index ddabfd1f27a..3d476b8bd5e 100644 --- a/java/ql/test/library-tests/frameworks/android/widget/test.ql +++ b/java/ql/test/library-tests/frameworks/android/widget/test.ql @@ -1,6 +1,7 @@ import java import semmle.code.java.dataflow.FlowSources import TestUtilities.InlineFlowTest +import DefaultFlowTest query predicate valueOf(MethodAccess ma) { ma.getMethod().hasQualifiedName("java.lang", "String", "valueOf") diff --git a/java/ql/test/library-tests/frameworks/apache-ant/test.expected b/java/ql/test/library-tests/frameworks/apache-ant/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/apache-ant/test.expected +++ b/java/ql/test/library-tests/frameworks/apache-ant/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/apache-ant/test.ql b/java/ql/test/library-tests/frameworks/apache-ant/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/apache-ant/test.ql +++ b/java/ql/test/library-tests/frameworks/apache-ant/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/apache-collections/test.expected b/java/ql/test/library-tests/frameworks/apache-collections/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/apache-collections/test.expected +++ b/java/ql/test/library-tests/frameworks/apache-collections/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/apache-collections/test.ql b/java/ql/test/library-tests/frameworks/apache-collections/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/apache-collections/test.ql +++ b/java/ql/test/library-tests/frameworks/apache-collections/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/apache-commons-compress/test.expected b/java/ql/test/library-tests/frameworks/apache-commons-compress/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/apache-commons-compress/test.expected +++ b/java/ql/test/library-tests/frameworks/apache-commons-compress/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/apache-commons-compress/test.ql b/java/ql/test/library-tests/frameworks/apache-commons-compress/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/apache-commons-compress/test.ql +++ b/java/ql/test/library-tests/frameworks/apache-commons-compress/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.expected b/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.expected +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.ql b/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.ql +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/apache-http/flow.expected b/java/ql/test/library-tests/frameworks/apache-http/flow.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/flow.expected +++ b/java/ql/test/library-tests/frameworks/apache-http/flow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/apache-http/flow.ql b/java/ql/test/library-tests/frameworks/apache-http/flow.ql index 20069103a4a..540b4847ff3 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/flow.ql +++ b/java/ql/test/library-tests/frameworks/apache-http/flow.ql @@ -21,10 +21,4 @@ module Config implements DataFlow::ConfigSig { } } -module Flow = TaintTracking::Global; - -class HasFlowTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { Flow::flow(src, sink) } -} +import TaintFlowTest diff --git a/java/ql/test/library-tests/frameworks/gson/test.expected b/java/ql/test/library-tests/frameworks/gson/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/gson/test.expected +++ b/java/ql/test/library-tests/frameworks/gson/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/gson/test.ql b/java/ql/test/library-tests/frameworks/gson/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/gson/test.ql +++ b/java/ql/test/library-tests/frameworks/gson/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/guava/generated/cache/test.expected b/java/ql/test/library-tests/frameworks/guava/generated/cache/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/guava/generated/cache/test.expected +++ b/java/ql/test/library-tests/frameworks/guava/generated/cache/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/guava/generated/cache/test.ql b/java/ql/test/library-tests/frameworks/guava/generated/cache/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/guava/generated/cache/test.ql +++ b/java/ql/test/library-tests/frameworks/guava/generated/cache/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/guava/generated/collect/test.expected b/java/ql/test/library-tests/frameworks/guava/generated/collect/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/guava/generated/collect/test.expected +++ b/java/ql/test/library-tests/frameworks/guava/generated/collect/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/guava/generated/collect/test.ql b/java/ql/test/library-tests/frameworks/guava/generated/collect/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/guava/generated/collect/test.ql +++ b/java/ql/test/library-tests/frameworks/guava/generated/collect/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/hudson/test.expected b/java/ql/test/library-tests/frameworks/hudson/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/hudson/test.expected +++ b/java/ql/test/library-tests/frameworks/hudson/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/hudson/test.ql b/java/ql/test/library-tests/frameworks/hudson/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/hudson/test.ql +++ b/java/ql/test/library-tests/frameworks/hudson/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/jackson/test.expected b/java/ql/test/library-tests/frameworks/jackson/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/jackson/test.expected +++ b/java/ql/test/library-tests/frameworks/jackson/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/jackson/test.ql b/java/ql/test/library-tests/frameworks/jackson/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/jackson/test.ql +++ b/java/ql/test/library-tests/frameworks/jackson/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/javax-json/test.expected b/java/ql/test/library-tests/frameworks/javax-json/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/javax-json/test.expected +++ b/java/ql/test/library-tests/frameworks/javax-json/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/javax-json/test.ql b/java/ql/test/library-tests/frameworks/javax-json/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/javax-json/test.ql +++ b/java/ql/test/library-tests/frameworks/javax-json/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/jdk/java.io/test.expected b/java/ql/test/library-tests/frameworks/jdk/java.io/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/jdk/java.io/test.expected +++ b/java/ql/test/library-tests/frameworks/jdk/java.io/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/jdk/java.io/test.ql b/java/ql/test/library-tests/frameworks/jdk/java.io/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/jdk/java.io/test.ql +++ b/java/ql/test/library-tests/frameworks/jdk/java.io/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/jdk/java.net/test.expected b/java/ql/test/library-tests/frameworks/jdk/java.net/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/jdk/java.net/test.expected +++ b/java/ql/test/library-tests/frameworks/jdk/java.net/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/jdk/java.net/test.ql b/java/ql/test/library-tests/frameworks/jdk/java.net/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/jdk/java.net/test.ql +++ b/java/ql/test/library-tests/frameworks/jdk/java.net/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/jdk/java.nio.file/test.expected b/java/ql/test/library-tests/frameworks/jdk/java.nio.file/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/jdk/java.nio.file/test.expected +++ b/java/ql/test/library-tests/frameworks/jdk/java.nio.file/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/jdk/java.nio.file/test.ql b/java/ql/test/library-tests/frameworks/jdk/java.nio.file/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/jdk/java.nio.file/test.ql +++ b/java/ql/test/library-tests/frameworks/jdk/java.nio.file/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/json-java/test.expected b/java/ql/test/library-tests/frameworks/json-java/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/json-java/test.expected +++ b/java/ql/test/library-tests/frameworks/json-java/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/json-java/test.ql b/java/ql/test/library-tests/frameworks/json-java/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/json-java/test.ql +++ b/java/ql/test/library-tests/frameworks/json-java/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/netty/generated/test.expected b/java/ql/test/library-tests/frameworks/netty/generated/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/netty/generated/test.expected +++ b/java/ql/test/library-tests/frameworks/netty/generated/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/netty/generated/test.ql b/java/ql/test/library-tests/frameworks/netty/generated/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/netty/generated/test.ql +++ b/java/ql/test/library-tests/frameworks/netty/generated/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/netty/manual/test.expected b/java/ql/test/library-tests/frameworks/netty/manual/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/netty/manual/test.expected +++ b/java/ql/test/library-tests/frameworks/netty/manual/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/netty/manual/test.ql b/java/ql/test/library-tests/frameworks/netty/manual/test.ql index 111db20f792..c67cf1835fa 100644 --- a/java/ql/test/library-tests/frameworks/netty/manual/test.ql +++ b/java/ql/test/library-tests/frameworks/netty/manual/test.ql @@ -13,10 +13,4 @@ module Config implements DataFlow::ConfigSig { predicate isSink = DefaultFlowConfig::isSink/1; } -module Flow = TaintTracking::Global; - -class Test extends InlineFlowTest { - override predicate hasTaintFlow(DataFlow::Node source, DataFlow::Node sink) { - Flow::flow(source, sink) - } -} +import FlowTest diff --git a/java/ql/test/library-tests/frameworks/okhttp/test.expected b/java/ql/test/library-tests/frameworks/okhttp/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/okhttp/test.expected +++ b/java/ql/test/library-tests/frameworks/okhttp/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/okhttp/test.ql b/java/ql/test/library-tests/frameworks/okhttp/test.ql index 52e8a47132a..04cb3e7f7ac 100644 --- a/java/ql/test/library-tests/frameworks/okhttp/test.ql +++ b/java/ql/test/library-tests/frameworks/okhttp/test.ql @@ -10,10 +10,4 @@ module OkHttpFlowConfig implements DataFlow::ConfigSig { } } -module OkHttpFlow = DataFlow::Global; - -class OkHttpTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { - OkHttpFlow::flow(src, sink) - } -} +import FlowTest diff --git a/java/ql/test/library-tests/frameworks/play/test.expected b/java/ql/test/library-tests/frameworks/play/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/play/test.expected +++ b/java/ql/test/library-tests/frameworks/play/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/play/test.ql b/java/ql/test/library-tests/frameworks/play/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/play/test.ql +++ b/java/ql/test/library-tests/frameworks/play/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/rabbitmq/FlowTest.expected b/java/ql/test/library-tests/frameworks/rabbitmq/FlowTest.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/rabbitmq/FlowTest.expected +++ b/java/ql/test/library-tests/frameworks/rabbitmq/FlowTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/rabbitmq/FlowTest.ql b/java/ql/test/library-tests/frameworks/rabbitmq/FlowTest.ql index 47cc6b07ad2..0adb5a87783 100644 --- a/java/ql/test/library-tests/frameworks/rabbitmq/FlowTest.ql +++ b/java/ql/test/library-tests/frameworks/rabbitmq/FlowTest.ql @@ -11,10 +11,4 @@ module Config implements DataFlow::ConfigSig { } } -module Flow = TaintTracking::Global; - -class HasFlowTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { Flow::flow(src, sink) } -} +import TaintFlowTest diff --git a/java/ql/test/library-tests/frameworks/ratpack/flow.expected b/java/ql/test/library-tests/frameworks/ratpack/flow.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/ratpack/flow.expected +++ b/java/ql/test/library-tests/frameworks/ratpack/flow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/ratpack/flow.ql b/java/ql/test/library-tests/frameworks/ratpack/flow.ql index dae21e78f7c..eab631f0589 100644 --- a/java/ql/test/library-tests/frameworks/ratpack/flow.ql +++ b/java/ql/test/library-tests/frameworks/ratpack/flow.ql @@ -15,12 +15,4 @@ module Config implements DataFlow::ConfigSig { } } -module Flow = TaintTracking::Global; - -class HasFlowTest extends InlineFlowTest { - HasFlowTest() { this = "HasFlowTest" } - - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { Flow::flow(src, sink) } -} +import TaintFlowTest diff --git a/java/ql/test/library-tests/frameworks/retrofit/test.expected b/java/ql/test/library-tests/frameworks/retrofit/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/retrofit/test.expected +++ b/java/ql/test/library-tests/frameworks/retrofit/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/retrofit/test.ql b/java/ql/test/library-tests/frameworks/retrofit/test.ql index e09f1ed41d7..0abbff1f958 100644 --- a/java/ql/test/library-tests/frameworks/retrofit/test.ql +++ b/java/ql/test/library-tests/frameworks/retrofit/test.ql @@ -10,8 +10,4 @@ module FlowConfig implements DataFlow::ConfigSig { } } -module Flow = DataFlow::Global; - -class RetrofitFlowTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { Flow::flow(src, sink) } -} +import FlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/beans/test.expected b/java/ql/test/library-tests/frameworks/spring/beans/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/beans/test.expected +++ b/java/ql/test/library-tests/frameworks/spring/beans/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/beans/test.ql b/java/ql/test/library-tests/frameworks/spring/beans/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/spring/beans/test.ql +++ b/java/ql/test/library-tests/frameworks/spring/beans/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/cache/test.expected b/java/ql/test/library-tests/frameworks/spring/cache/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/cache/test.expected +++ b/java/ql/test/library-tests/frameworks/spring/cache/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/cache/test.ql b/java/ql/test/library-tests/frameworks/spring/cache/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/spring/cache/test.ql +++ b/java/ql/test/library-tests/frameworks/spring/cache/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/context/flow.expected b/java/ql/test/library-tests/frameworks/spring/context/flow.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/context/flow.expected +++ b/java/ql/test/library-tests/frameworks/spring/context/flow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/context/flow.ql b/java/ql/test/library-tests/frameworks/spring/context/flow.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/spring/context/flow.ql +++ b/java/ql/test/library-tests/frameworks/spring/context/flow.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/controller/test.expected b/java/ql/test/library-tests/frameworks/spring/controller/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/controller/test.expected +++ b/java/ql/test/library-tests/frameworks/spring/controller/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/controller/test.ql b/java/ql/test/library-tests/frameworks/spring/controller/test.ql index b6beb8e1e75..35b3d064e5a 100644 --- a/java/ql/test/library-tests/frameworks/spring/controller/test.ql +++ b/java/ql/test/library-tests/frameworks/spring/controller/test.ql @@ -10,10 +10,4 @@ module ValueFlowConfig implements DataFlow::ConfigSig { } } -module ValueFlow = DataFlow::Global; - -class Test extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { - ValueFlow::flow(src, sink) - } -} +import FlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/data/test.expected b/java/ql/test/library-tests/frameworks/spring/data/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/data/test.expected +++ b/java/ql/test/library-tests/frameworks/spring/data/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/data/test.ql b/java/ql/test/library-tests/frameworks/spring/data/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/spring/data/test.ql +++ b/java/ql/test/library-tests/frameworks/spring/data/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/http/flow.expected b/java/ql/test/library-tests/frameworks/spring/http/flow.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/http/flow.expected +++ b/java/ql/test/library-tests/frameworks/spring/http/flow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/http/flow.ql b/java/ql/test/library-tests/frameworks/spring/http/flow.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/spring/http/flow.ql +++ b/java/ql/test/library-tests/frameworks/spring/http/flow.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/ui/test.expected b/java/ql/test/library-tests/frameworks/spring/ui/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/ui/test.expected +++ b/java/ql/test/library-tests/frameworks/spring/ui/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/ui/test.ql b/java/ql/test/library-tests/frameworks/spring/ui/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/spring/ui/test.ql +++ b/java/ql/test/library-tests/frameworks/spring/ui/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/util/test.expected b/java/ql/test/library-tests/frameworks/spring/util/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/util/test.expected +++ b/java/ql/test/library-tests/frameworks/spring/util/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/util/test.ql b/java/ql/test/library-tests/frameworks/spring/util/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/spring/util/test.ql +++ b/java/ql/test/library-tests/frameworks/spring/util/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/validation/test.expected b/java/ql/test/library-tests/frameworks/spring/validation/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/validation/test.expected +++ b/java/ql/test/library-tests/frameworks/spring/validation/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/validation/test.ql b/java/ql/test/library-tests/frameworks/spring/validation/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/spring/validation/test.ql +++ b/java/ql/test/library-tests/frameworks/spring/validation/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/webmultipart/test.expected b/java/ql/test/library-tests/frameworks/spring/webmultipart/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/webmultipart/test.expected +++ b/java/ql/test/library-tests/frameworks/spring/webmultipart/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/webmultipart/test.ql b/java/ql/test/library-tests/frameworks/spring/webmultipart/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/spring/webmultipart/test.ql +++ b/java/ql/test/library-tests/frameworks/spring/webmultipart/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/spring/webutil/test.expected b/java/ql/test/library-tests/frameworks/spring/webutil/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/spring/webutil/test.expected +++ b/java/ql/test/library-tests/frameworks/spring/webutil/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/spring/webutil/test.ql b/java/ql/test/library-tests/frameworks/spring/webutil/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/spring/webutil/test.ql +++ b/java/ql/test/library-tests/frameworks/spring/webutil/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/stapler/test.expected b/java/ql/test/library-tests/frameworks/stapler/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/stapler/test.expected +++ b/java/ql/test/library-tests/frameworks/stapler/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/stapler/test.ql b/java/ql/test/library-tests/frameworks/stapler/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/stapler/test.ql +++ b/java/ql/test/library-tests/frameworks/stapler/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/stream/test.expected b/java/ql/test/library-tests/frameworks/stream/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/stream/test.expected +++ b/java/ql/test/library-tests/frameworks/stream/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/stream/test.ql b/java/ql/test/library-tests/frameworks/stream/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/stream/test.ql +++ b/java/ql/test/library-tests/frameworks/stream/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/frameworks/thymeleaf/test.expected b/java/ql/test/library-tests/frameworks/thymeleaf/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/frameworks/thymeleaf/test.expected +++ b/java/ql/test/library-tests/frameworks/thymeleaf/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/frameworks/thymeleaf/test.ql b/java/ql/test/library-tests/frameworks/thymeleaf/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/frameworks/thymeleaf/test.ql +++ b/java/ql/test/library-tests/frameworks/thymeleaf/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/logging/test.expected b/java/ql/test/library-tests/logging/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/logging/test.expected +++ b/java/ql/test/library-tests/logging/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/logging/test.ql b/java/ql/test/library-tests/logging/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/logging/test.ql +++ b/java/ql/test/library-tests/logging/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/optional/test.expected b/java/ql/test/library-tests/optional/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/optional/test.expected +++ b/java/ql/test/library-tests/optional/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/optional/test.ql b/java/ql/test/library-tests/optional/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/optional/test.ql +++ b/java/ql/test/library-tests/optional/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/paths/test.expected b/java/ql/test/library-tests/paths/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/paths/test.expected +++ b/java/ql/test/library-tests/paths/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/paths/test.ql b/java/ql/test/library-tests/paths/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/paths/test.ql +++ b/java/ql/test/library-tests/paths/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/pathsanitizer/test.expected b/java/ql/test/library-tests/pathsanitizer/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/pathsanitizer/test.expected +++ b/java/ql/test/library-tests/pathsanitizer/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/pathsanitizer/test.ql b/java/ql/test/library-tests/pathsanitizer/test.ql index cefce3276e6..0a20ad012b9 100644 --- a/java/ql/test/library-tests/pathsanitizer/test.ql +++ b/java/ql/test/library-tests/pathsanitizer/test.ql @@ -10,12 +10,4 @@ module PathSanitizerConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof PathInjectionSanitizer } } -module PathSanitizerFlow = TaintTracking::Global; - -class Test extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - PathSanitizerFlow::flow(src, sink) - } -} +import TaintFlowTest diff --git a/java/ql/test/library-tests/regex/test.expected b/java/ql/test/library-tests/regex/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/regex/test.expected +++ b/java/ql/test/library-tests/regex/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/regex/test.ql b/java/ql/test/library-tests/regex/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/regex/test.ql +++ b/java/ql/test/library-tests/regex/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/library-tests/scanner/test.expected b/java/ql/test/library-tests/scanner/test.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/library-tests/scanner/test.expected +++ b/java/ql/test/library-tests/scanner/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/library-tests/scanner/test.ql b/java/ql/test/library-tests/scanner/test.ql index 5d91e4e8e26..aca87429a3a 100644 --- a/java/ql/test/library-tests/scanner/test.ql +++ b/java/ql/test/library-tests/scanner/test.ql @@ -1,2 +1,3 @@ import java import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/java/ql/test/query-tests/security/CWE-117/LogInjectionTest.expected b/java/ql/test/query-tests/security/CWE-117/LogInjectionTest.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/query-tests/security/CWE-117/LogInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-117/LogInjectionTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/query-tests/security/CWE-117/LogInjectionTest.ql b/java/ql/test/query-tests/security/CWE-117/LogInjectionTest.ql index 73a41b1bd8e..a2707b5df44 100644 --- a/java/ql/test/query-tests/security/CWE-117/LogInjectionTest.ql +++ b/java/ql/test/query-tests/security/CWE-117/LogInjectionTest.ql @@ -8,10 +8,4 @@ private class TestSource extends RemoteFlowSource { override string getSourceType() { result = "test source" } } -private class LogInjectionTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - LogInjectionFlow::flow(src, sink) - } -} +import TaintFlowTest diff --git a/java/ql/test/query-tests/security/CWE-266/IntentUriPermissionManipulationTest.expected b/java/ql/test/query-tests/security/CWE-266/IntentUriPermissionManipulationTest.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/query-tests/security/CWE-266/IntentUriPermissionManipulationTest.expected +++ b/java/ql/test/query-tests/security/CWE-266/IntentUriPermissionManipulationTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/query-tests/security/CWE-266/IntentUriPermissionManipulationTest.ql b/java/ql/test/query-tests/security/CWE-266/IntentUriPermissionManipulationTest.ql index d90039cf920..86feb7843ce 100644 --- a/java/ql/test/query-tests/security/CWE-266/IntentUriPermissionManipulationTest.ql +++ b/java/ql/test/query-tests/security/CWE-266/IntentUriPermissionManipulationTest.ql @@ -1,11 +1,4 @@ import java import TestUtilities.InlineFlowTest import semmle.code.java.security.IntentUriPermissionManipulationQuery - -class IntentUriPermissionManipulationTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - IntentUriPermissionManipulationFlow::flow(src, sink) - } -} +import TaintFlowTest diff --git a/java/ql/test/query-tests/security/CWE-441/UnsafeContentUriResolutionTest.expected b/java/ql/test/query-tests/security/CWE-441/UnsafeContentUriResolutionTest.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/query-tests/security/CWE-441/UnsafeContentUriResolutionTest.expected +++ b/java/ql/test/query-tests/security/CWE-441/UnsafeContentUriResolutionTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/query-tests/security/CWE-441/UnsafeContentUriResolutionTest.ql b/java/ql/test/query-tests/security/CWE-441/UnsafeContentUriResolutionTest.ql index 55c07bbd301..ae1258a66c5 100644 --- a/java/ql/test/query-tests/security/CWE-441/UnsafeContentUriResolutionTest.ql +++ b/java/ql/test/query-tests/security/CWE-441/UnsafeContentUriResolutionTest.ql @@ -1,11 +1,4 @@ import java import TestUtilities.InlineFlowTest import semmle.code.java.security.UnsafeContentUriResolutionQuery - -class Test extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - UnsafeContentResolutionFlow::flow(src, sink) - } -} +import TaintFlowTest diff --git a/java/ql/test/query-tests/security/CWE-470/FragmentInjectionTest.expected b/java/ql/test/query-tests/security/CWE-470/FragmentInjectionTest.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/query-tests/security/CWE-470/FragmentInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-470/FragmentInjectionTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/query-tests/security/CWE-470/FragmentInjectionTest.ql b/java/ql/test/query-tests/security/CWE-470/FragmentInjectionTest.ql index 2771dd3af90..a1cff04f4c6 100644 --- a/java/ql/test/query-tests/security/CWE-470/FragmentInjectionTest.ql +++ b/java/ql/test/query-tests/security/CWE-470/FragmentInjectionTest.ql @@ -1,11 +1,4 @@ import java import semmle.code.java.security.FragmentInjectionQuery import TestUtilities.InlineFlowTest - -class Test extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - FragmentInjectionTaintFlow::flow(src, sink) - } -} +import TaintFlowTest diff --git a/java/ql/test/query-tests/security/CWE-489/webview-debugging/WebviewDebuggingEnabled.expected b/java/ql/test/query-tests/security/CWE-489/webview-debugging/WebviewDebuggingEnabled.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/query-tests/security/CWE-489/webview-debugging/WebviewDebuggingEnabled.expected +++ b/java/ql/test/query-tests/security/CWE-489/webview-debugging/WebviewDebuggingEnabled.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/query-tests/security/CWE-489/webview-debugging/WebviewDebuggingEnabled.ql b/java/ql/test/query-tests/security/CWE-489/webview-debugging/WebviewDebuggingEnabled.ql index 5bd19fb5b9e..99ac3d4e03c 100644 --- a/java/ql/test/query-tests/security/CWE-489/webview-debugging/WebviewDebuggingEnabled.ql +++ b/java/ql/test/query-tests/security/CWE-489/webview-debugging/WebviewDebuggingEnabled.ql @@ -1,11 +1,4 @@ import java import TestUtilities.InlineFlowTest import semmle.code.java.security.WebviewDebuggingEnabledQuery - -class HasFlowTest extends InlineFlowTest { - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { - WebviewDebugEnabledFlow::flow(src, sink) - } -} +import ValueFlowTest diff --git a/java/ql/test/query-tests/security/CWE-532/SensitiveLogInfo.expected b/java/ql/test/query-tests/security/CWE-532/SensitiveLogInfo.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/query-tests/security/CWE-532/SensitiveLogInfo.expected +++ b/java/ql/test/query-tests/security/CWE-532/SensitiveLogInfo.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/query-tests/security/CWE-532/SensitiveLogInfo.ql b/java/ql/test/query-tests/security/CWE-532/SensitiveLogInfo.ql index 5de153a9e35..389cff934a9 100644 --- a/java/ql/test/query-tests/security/CWE-532/SensitiveLogInfo.ql +++ b/java/ql/test/query-tests/security/CWE-532/SensitiveLogInfo.ql @@ -1,11 +1,4 @@ import java import TestUtilities.InlineFlowTest import semmle.code.java.security.SensitiveLoggingQuery - -class HasFlowTest extends InlineFlowTest { - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - SensitiveLoggerFlow::flow(src, sink) - } - - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } -} +import TaintFlowTest diff --git a/java/ql/test/query-tests/security/CWE-611/XXE.expected b/java/ql/test/query-tests/security/CWE-611/XXE.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/query-tests/security/CWE-611/XXE.expected +++ b/java/ql/test/query-tests/security/CWE-611/XXE.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/query-tests/security/CWE-611/XXE.ql b/java/ql/test/query-tests/security/CWE-611/XXE.ql index f1463f561f3..ed12823a6bb 100644 --- a/java/ql/test/query-tests/security/CWE-611/XXE.ql +++ b/java/ql/test/query-tests/security/CWE-611/XXE.ql @@ -1,11 +1,4 @@ import java import TestUtilities.InlineFlowTest import semmle.code.java.security.XxeRemoteQuery - -class HasFlowTest extends InlineFlowTest { - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - XxeFlow::flow(src, sink) - } - - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } -} +import TaintFlowTest diff --git a/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.expected b/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.expected +++ b/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.ql b/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.ql index 01af77284f0..c1bc2049c76 100644 --- a/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.ql +++ b/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.ql @@ -2,11 +2,4 @@ import java import TestUtilities.InlineExpectationsTest import TestUtilities.InlineFlowTest import semmle.code.java.security.RsaWithoutOaepQuery - -class HasFlowTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - RsaWithoutOaepFlow::flow(src, sink) - } -} +import TaintFlowTest diff --git a/java/ql/test/query-tests/security/CWE-927/SensitiveCommunication.expected b/java/ql/test/query-tests/security/CWE-927/SensitiveCommunication.expected index e69de29bb2d..48de9172b36 100644 --- a/java/ql/test/query-tests/security/CWE-927/SensitiveCommunication.expected +++ b/java/ql/test/query-tests/security/CWE-927/SensitiveCommunication.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/java/ql/test/query-tests/security/CWE-927/SensitiveCommunication.ql b/java/ql/test/query-tests/security/CWE-927/SensitiveCommunication.ql index 0f1864398b4..cf7e46b6e8e 100644 --- a/java/ql/test/query-tests/security/CWE-927/SensitiveCommunication.ql +++ b/java/ql/test/query-tests/security/CWE-927/SensitiveCommunication.ql @@ -2,11 +2,4 @@ import java import semmle.code.java.security.AndroidSensitiveCommunicationQuery import TestUtilities.InlineExpectationsTest import TestUtilities.InlineFlowTest - -class HasFlowTest extends InlineFlowTest { - override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() } - - override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) { - SensitiveCommunicationFlow::flow(src, sink) - } -} +import TaintFlowTest From d82c3ce11ac9efdab8e2d835fa5ca40cff41fda4 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 14 Jun 2023 18:07:57 +0200 Subject: [PATCH 129/364] Ruby: Rewrite `InlineFlowTest` as a parameterized module --- .../2023-06-14-insecure-download-config.md | 4 + .../ruby/security/InsecureDownloadQuery.qll | 29 ++++- .../security/cwe-829/InsecureDownload.ql | 6 +- ruby/ql/test/TestUtilities/InlineFlowTest.qll | 113 ++++++++---------- .../dataflow/array-flow/array-flow.expected | 1 + .../dataflow/array-flow/array-flow.ql | 5 +- .../call-sensitivity.expected | 1 + .../call-sensitivity/call-sensitivity.ql | 7 +- .../flow-summaries/semantics.expected | 1 + .../dataflow/flow-summaries/semantics.ql | 1 + .../dataflow/global/Flow.expected | 1 + .../library-tests/dataflow/global/Flow.ql | 7 +- .../dataflow/hash-flow/hash-flow.expected | 1 + .../dataflow/hash-flow/hash-flow.ql | 9 +- .../dataflow/local/InlineFlowTest.expected | 1 + .../dataflow/local/InlineFlowTest.ql | 5 +- .../dataflow/params/params-flow.expected | 1 + .../dataflow/params/params-flow.ql | 9 +- .../pathname-flow/pathame-flow.expected | 1 + .../dataflow/pathname-flow/pathame-flow.ql | 5 +- .../dataflow/ssa-flow/ssa-flow.expected | 1 + .../dataflow/ssa-flow/ssa-flow.ql | 5 +- .../dataflow/string-flow/string-flow.expected | 1 + .../dataflow/string-flow/string-flow.ql | 5 +- .../dataflow/summaries/Summaries.expected | 1 + .../dataflow/summaries/Summaries.ql | 22 ++-- .../action_controller/params-flow.expected | 1 + .../action_controller/params-flow.ql | 14 ++- .../action_mailer/params-flow.expected | 1 + .../frameworks/action_mailer/params-flow.ql | 14 ++- .../ActiveSupportDataFlow.expected | 1 + .../active_support/ActiveSupportDataFlow.ql | 5 +- .../frameworks/arel/Arel.expected | 1 + .../library-tests/frameworks/arel/Arel.ql | 5 +- .../frameworks/json/JsonDataFlow.expected | 1 + .../frameworks/json/JsonDataFlow.ql | 1 + .../frameworks/sinatra/Flow.expected | 1 + .../library-tests/frameworks/sinatra/Flow.ql | 12 +- .../cwe-829/InsecureDownload.expected | 1 + .../security/cwe-829/InsecureDownload.ql | 27 +++-- 40 files changed, 188 insertions(+), 140 deletions(-) create mode 100644 ruby/ql/lib/change-notes/2023-06-14-insecure-download-config.md diff --git a/ruby/ql/lib/change-notes/2023-06-14-insecure-download-config.md b/ruby/ql/lib/change-notes/2023-06-14-insecure-download-config.md new file mode 100644 index 00000000000..6bf019cd051 --- /dev/null +++ b/ruby/ql/lib/change-notes/2023-06-14-insecure-download-config.md @@ -0,0 +1,4 @@ +--- +category: deprecated +--- +* The `Configuration` taint flow configuration class from `codeql.ruby.security.InsecureDownloadQuery` has been deprecated. Use the `Flow` module instead. diff --git a/ruby/ql/lib/codeql/ruby/security/InsecureDownloadQuery.qll b/ruby/ql/lib/codeql/ruby/security/InsecureDownloadQuery.qll index b701a3d1dd4..0b4c63f4392 100644 --- a/ruby/ql/lib/codeql/ruby/security/InsecureDownloadQuery.qll +++ b/ruby/ql/lib/codeql/ruby/security/InsecureDownloadQuery.qll @@ -13,7 +13,7 @@ import InsecureDownloadCustomizations::InsecureDownload /** * A taint tracking configuration for download of sensitive file through insecure connection. */ -class Configuration extends DataFlow::Configuration { +deprecated class Configuration extends DataFlow::Configuration { Configuration() { this = "InsecureDownload" } override predicate isSource(DataFlow::Node source, DataFlow::FlowState label) { @@ -29,3 +29,30 @@ class Configuration extends DataFlow::Configuration { node instanceof Sanitizer } } + +/** + * A taint tracking configuration for download of sensitive file through insecure connection. + */ +module Config implements DataFlow::StateConfigSig { + class FlowState = string; + + predicate isSource(DataFlow::Node source, DataFlow::FlowState label) { + source.(Source).getALabel() = label + } + + predicate isSink(DataFlow::Node sink, DataFlow::FlowState label) { + sink.(Sink).getALabel() = label + } + + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } + + predicate isBarrier(DataFlow::Node node, FlowState state) { none() } + + predicate isAdditionalFlowStep( + DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2 + ) { + none() + } +} + +module Flow = DataFlow::GlobalWithState; diff --git a/ruby/ql/src/queries/security/cwe-829/InsecureDownload.ql b/ruby/ql/src/queries/security/cwe-829/InsecureDownload.ql index b5f2610ae2e..cdd494134a5 100644 --- a/ruby/ql/src/queries/security/cwe-829/InsecureDownload.ql +++ b/ruby/ql/src/queries/security/cwe-829/InsecureDownload.ql @@ -14,9 +14,9 @@ import codeql.ruby.AST import codeql.ruby.DataFlow import codeql.ruby.security.InsecureDownloadQuery -import DataFlow::PathGraph +import Flow::PathGraph -from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasFlowPath(source, sink) +from Flow::PathNode source, Flow::PathNode sink +where Flow::flowPath(source, sink) select sink.getNode(), source, sink, "$@ of sensitive file from $@.", sink.getNode().(Sink).getDownloadCall(), "Download", source.getNode(), "HTTP source" diff --git a/ruby/ql/test/TestUtilities/InlineFlowTest.qll b/ruby/ql/test/TestUtilities/InlineFlowTest.qll index d653a3e414e..af83862803c 100644 --- a/ruby/ql/test/TestUtilities/InlineFlowTest.qll +++ b/ruby/ql/test/TestUtilities/InlineFlowTest.qll @@ -4,10 +4,11 @@ * Example for a test.ql: * ```ql * import TestUtilities.InlineFlowTest + * import DefaultFlowTest * import PathGraph * - * from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf - * where conf.hasFlowPath(source, sink) + * from ValueFlow::PathNode source, ValueFlow::PathNode sink + * where ValueFlow::flowPath(source, sink) * select sink, source, sink, "$@", source, source.toString() * ``` * @@ -20,14 +21,10 @@ * sink(t); // $ hasTaintFlow=2 * ``` * - * If you're not interested in a specific flow type, you can disable either value or taint flow expectations as follows: - * ```ql - * class HasFlowTest extends InlineFlowTest { - * override DataFlow::Configuration getTaintFlowConfig() { none() } - * - * override DataFlow::Configuration getValueFlowConfig() { none() } - * } - * ``` + * If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import + * `ValueFlowTest`. Similarly, if you are only interested in taint flow, then instead of + * importing `DefaultFlowTest`, you can import `TaintFlowTest`. In both cases + * `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`. * * If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`. */ @@ -38,72 +35,62 @@ import codeql.ruby.TaintTracking import TestUtilities.InlineExpectationsTest import TestUtilities.InlineFlowTestUtil -class DefaultValueFlowConf extends DataFlow::Configuration { - DefaultValueFlowConf() { this = "qltest:defaultValueFlowConf" } +module DefaultFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { defaultSource(source) } - override predicate isSource(DataFlow::Node n) { defaultSource(n) } + predicate isSink(DataFlow::Node sink) { defaultSink(sink) } - override predicate isSink(DataFlow::Node n) { defaultSink(n) } - - override int fieldFlowBranchLimit() { result = 1000 } + int fieldFlowBranchLimit() { result = 1000 } } -class DefaultTaintFlowConf extends TaintTracking::Configuration { - DefaultTaintFlowConf() { this = "qltest:defaultTaintFlowConf" } +private module NoFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { none() } - override predicate isSource(DataFlow::Node n) { defaultSource(n) } - - override predicate isSink(DataFlow::Node n) { defaultSink(n) } - - override int fieldFlowBranchLimit() { result = 1000 } + predicate isSink(DataFlow::Node sink) { none() } } -class InlineFlowTest extends InlineExpectationsTest { - InlineFlowTest() { this = "HasFlowTest" } +module FlowTest { + module ValueFlow = DataFlow::Global; - override string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] } + module TaintFlow = TaintTracking::Global; - override predicate hasActualResult(Location location, string element, string tag, string value) { - tag = "hasValueFlow" and - exists(DataFlow::Node src, DataFlow::Node sink | this.getValueFlowConfig().hasFlow(src, sink) | - sink.getLocation() = location and - element = sink.toString() and - if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" - ) - or - tag = "hasTaintFlow" and - exists(DataFlow::Node src, DataFlow::Node sink | - this.getTaintFlowConfig().hasFlow(src, sink) and - not this.getValueFlowConfig().hasFlow(src, sink) - | - sink.getLocation() = location and - element = sink.toString() and - if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" - ) - } + private module InlineTest implements TestSig { + string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] } - DataFlow::Configuration getValueFlowConfig() { result = any(DefaultValueFlowConf config) } - - DataFlow::Configuration getTaintFlowConfig() { result = any(DefaultTaintFlowConf config) } -} - -module PathGraph { - private import DataFlow::PathGraph as PG - - private class PathNode extends DataFlow::PathNode { - PathNode() { - this.getConfiguration() = - [any(InlineFlowTest t).getValueFlowConfig(), any(InlineFlowTest t).getTaintFlowConfig()] + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasValueFlow" and + exists(DataFlow::Node src, DataFlow::Node sink | ValueFlow::flow(src, sink) | + sink.getLocation() = location and + element = sink.toString() and + if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" + ) + or + tag = "hasTaintFlow" and + exists(DataFlow::Node src, DataFlow::Node sink | + TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink) + | + sink.getLocation() = location and + element = sink.toString() and + if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" + ) } } - /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ - query predicate edges(PathNode a, PathNode b) { PG::edges(a, b) } + import MakeTest + import DataFlow::MergePathGraph - /** Holds if `n` is a node in the graph of data flow path explanations. */ - query predicate nodes(PathNode n, string key, string val) { PG::nodes(n, key, val) } - - query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { - PG::subpaths(arg, par, ret, out) + predicate flowPath(PathNode source, PathNode sink) { + ValueFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) or + TaintFlow::flowPath(source.asPathNode2(), sink.asPathNode2()) } } + +module DefaultFlowTest = FlowTest; + +module ValueFlowTest { + import FlowTest +} + +module TaintFlowTest { + import FlowTest +} diff --git a/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected b/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected index d258253537a..b406f9feecb 100644 --- a/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected @@ -1,4 +1,5 @@ failures +testFailures edges | array_flow.rb:2:5:2:5 | a [element 0] | array_flow.rb:3:10:3:10 | a [element 0] | | array_flow.rb:2:5:2:5 | a [element 0] | array_flow.rb:3:10:3:10 | a [element 0] | diff --git a/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.ql b/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.ql index 0c4597b8f07..dfd6242a414 100644 --- a/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.ql +++ b/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.ql @@ -4,8 +4,9 @@ import codeql.ruby.AST import TestUtilities.InlineFlowTest +import DefaultFlowTest import PathGraph -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf -where conf.hasFlowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/call-sensitivity/call-sensitivity.expected b/ruby/ql/test/library-tests/dataflow/call-sensitivity/call-sensitivity.expected index 58d5861bae9..a3ea8f01feb 100644 --- a/ruby/ql/test/library-tests/dataflow/call-sensitivity/call-sensitivity.expected +++ b/ruby/ql/test/library-tests/dataflow/call-sensitivity/call-sensitivity.expected @@ -1,4 +1,5 @@ failures +testFailures edges | call_sensitivity.rb:9:7:9:13 | call to taint | call_sensitivity.rb:9:6:9:14 | ( ... ) | | call_sensitivity.rb:9:7:9:13 | call to taint | call_sensitivity.rb:9:6:9:14 | ( ... ) | diff --git a/ruby/ql/test/library-tests/dataflow/call-sensitivity/call-sensitivity.ql b/ruby/ql/test/library-tests/dataflow/call-sensitivity/call-sensitivity.ql index 6403c4b04c2..08c0fa8fc45 100644 --- a/ruby/ql/test/library-tests/dataflow/call-sensitivity/call-sensitivity.ql +++ b/ruby/ql/test/library-tests/dataflow/call-sensitivity/call-sensitivity.ql @@ -5,13 +5,14 @@ import codeql.ruby.AST import codeql.ruby.DataFlow import TestUtilities.InlineFlowTest -import DataFlow::PathGraph +import DefaultFlowTest +import PathGraph import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch query predicate mayBenefitFromCallContext = DataFlowDispatch::mayBenefitFromCallContext/2; query predicate viableImplInCallContext = DataFlowDispatch::viableImplInCallContext/2; -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultTaintFlowConf conf -where conf.hasFlowPath(source, sink) +from TaintFlow::PathNode source, TaintFlow::PathNode sink +where TaintFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.expected b/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.expected index fc781f05d3c..b3e010e86b6 100644 --- a/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.expected +++ b/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.expected @@ -1,4 +1,5 @@ failures +testFailures edges | semantics.rb:2:5:2:5 | a | semantics.rb:3:9:3:9 | a | | semantics.rb:2:5:2:5 | a | semantics.rb:3:9:3:9 | a | diff --git a/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.ql b/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.ql index 9733e0c5393..c3c2e45322a 100644 --- a/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.ql +++ b/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.ql @@ -5,6 +5,7 @@ import codeql.ruby.AST import TestUtilities.InlineFlowTest +import DefaultFlowTest import PathGraph private import codeql.ruby.dataflow.FlowSummary diff --git a/ruby/ql/test/library-tests/dataflow/global/Flow.expected b/ruby/ql/test/library-tests/dataflow/global/Flow.expected index 63359aa9a36..5ddbe3ce98c 100644 --- a/ruby/ql/test/library-tests/dataflow/global/Flow.expected +++ b/ruby/ql/test/library-tests/dataflow/global/Flow.expected @@ -1,4 +1,5 @@ failures +testFailures edges | captured_variables.rb:1:24:1:24 | x | captured_variables.rb:2:20:2:20 | x | | captured_variables.rb:1:24:1:24 | x | captured_variables.rb:2:20:2:20 | x | diff --git a/ruby/ql/test/library-tests/dataflow/global/Flow.ql b/ruby/ql/test/library-tests/dataflow/global/Flow.ql index 33825f765c2..64ce30508fb 100644 --- a/ruby/ql/test/library-tests/dataflow/global/Flow.ql +++ b/ruby/ql/test/library-tests/dataflow/global/Flow.ql @@ -5,8 +5,9 @@ import codeql.ruby.AST import codeql.ruby.DataFlow private import TestUtilities.InlineFlowTest -import DataFlow::PathGraph +import DefaultFlowTest +import PathGraph -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultTaintFlowConf conf -where conf.hasFlowPath(source, sink) +from TaintFlow::PathNode source, TaintFlow::PathNode sink +where TaintFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected b/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected index fff890f80b9..7be100aa1fe 100644 --- a/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected @@ -1,4 +1,5 @@ failures +testFailures edges | hash_flow.rb:10:5:10:8 | hash [element 0] | hash_flow.rb:30:10:30:13 | hash [element 0] | | hash_flow.rb:10:5:10:8 | hash [element :a] | hash_flow.rb:22:10:22:13 | hash [element :a] | diff --git a/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.ql b/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.ql index bb1b611d7fc..31941897936 100644 --- a/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.ql +++ b/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.ql @@ -4,12 +4,9 @@ import codeql.ruby.AST import TestUtilities.InlineFlowTest +import ValueFlowTest import PathGraph -class HasFlowTest extends InlineFlowTest { - override DataFlow::Configuration getTaintFlowConfig() { none() } -} - -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf -where conf.hasFlowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/local/InlineFlowTest.expected b/ruby/ql/test/library-tests/dataflow/local/InlineFlowTest.expected index b5ad38dfcbb..d979e6f052a 100644 --- a/ruby/ql/test/library-tests/dataflow/local/InlineFlowTest.expected +++ b/ruby/ql/test/library-tests/dataflow/local/InlineFlowTest.expected @@ -1,4 +1,5 @@ failures +testFailures edges | local_dataflow.rb:78:3:78:3 | z | local_dataflow.rb:89:8:89:8 | z | | local_dataflow.rb:78:12:78:20 | call to source | local_dataflow.rb:79:13:79:13 | b | diff --git a/ruby/ql/test/library-tests/dataflow/local/InlineFlowTest.ql b/ruby/ql/test/library-tests/dataflow/local/InlineFlowTest.ql index 4f6740c7e17..9a5ca73aa12 100644 --- a/ruby/ql/test/library-tests/dataflow/local/InlineFlowTest.ql +++ b/ruby/ql/test/library-tests/dataflow/local/InlineFlowTest.ql @@ -4,8 +4,9 @@ import codeql.ruby.AST import TestUtilities.InlineFlowTest +import DefaultFlowTest import PathGraph -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultTaintFlowConf conf -where conf.hasFlowPath(source, sink) +from TaintFlow::PathNode source, TaintFlow::PathNode sink +where TaintFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/params/params-flow.expected b/ruby/ql/test/library-tests/dataflow/params/params-flow.expected index cd2d1c87b28..b54948d17a4 100644 --- a/ruby/ql/test/library-tests/dataflow/params/params-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/params/params-flow.expected @@ -1,4 +1,5 @@ failures +testFailures edges | params_flow.rb:9:16:9:17 | p1 | params_flow.rb:10:10:10:11 | p1 | | params_flow.rb:9:20:9:21 | p2 | params_flow.rb:11:10:11:11 | p2 | diff --git a/ruby/ql/test/library-tests/dataflow/params/params-flow.ql b/ruby/ql/test/library-tests/dataflow/params/params-flow.ql index bb1b611d7fc..31941897936 100644 --- a/ruby/ql/test/library-tests/dataflow/params/params-flow.ql +++ b/ruby/ql/test/library-tests/dataflow/params/params-flow.ql @@ -4,12 +4,9 @@ import codeql.ruby.AST import TestUtilities.InlineFlowTest +import ValueFlowTest import PathGraph -class HasFlowTest extends InlineFlowTest { - override DataFlow::Configuration getTaintFlowConfig() { none() } -} - -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf -where conf.hasFlowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/pathname-flow/pathame-flow.expected b/ruby/ql/test/library-tests/dataflow/pathname-flow/pathame-flow.expected index 37a7d126193..44fc7a3d3d9 100644 --- a/ruby/ql/test/library-tests/dataflow/pathname-flow/pathame-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/pathname-flow/pathame-flow.expected @@ -1,4 +1,5 @@ failures +testFailures edges | pathname_flow.rb:4:5:4:6 | pn | pathname_flow.rb:5:10:5:11 | pn | | pathname_flow.rb:4:10:4:33 | call to new | pathname_flow.rb:4:5:4:6 | pn | diff --git a/ruby/ql/test/library-tests/dataflow/pathname-flow/pathame-flow.ql b/ruby/ql/test/library-tests/dataflow/pathname-flow/pathame-flow.ql index 0c4597b8f07..dfd6242a414 100644 --- a/ruby/ql/test/library-tests/dataflow/pathname-flow/pathame-flow.ql +++ b/ruby/ql/test/library-tests/dataflow/pathname-flow/pathame-flow.ql @@ -4,8 +4,9 @@ import codeql.ruby.AST import TestUtilities.InlineFlowTest +import DefaultFlowTest import PathGraph -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf -where conf.hasFlowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/ssa-flow/ssa-flow.expected b/ruby/ql/test/library-tests/dataflow/ssa-flow/ssa-flow.expected index e1e2893fad6..744c508f33f 100644 --- a/ruby/ql/test/library-tests/dataflow/ssa-flow/ssa-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/ssa-flow/ssa-flow.expected @@ -1,4 +1,5 @@ failures +testFailures edges | ssa_flow.rb:12:9:12:9 | [post] a [element 0] | ssa_flow.rb:16:10:16:10 | a [element 0] | | ssa_flow.rb:12:9:12:9 | [post] a [element 0] | ssa_flow.rb:16:10:16:10 | a [element 0] | diff --git a/ruby/ql/test/library-tests/dataflow/ssa-flow/ssa-flow.ql b/ruby/ql/test/library-tests/dataflow/ssa-flow/ssa-flow.ql index 0c4597b8f07..dfd6242a414 100644 --- a/ruby/ql/test/library-tests/dataflow/ssa-flow/ssa-flow.ql +++ b/ruby/ql/test/library-tests/dataflow/ssa-flow/ssa-flow.ql @@ -4,8 +4,9 @@ import codeql.ruby.AST import TestUtilities.InlineFlowTest +import DefaultFlowTest import PathGraph -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf -where conf.hasFlowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.expected b/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.expected index 4cab79b9e42..57eb688e6af 100644 --- a/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.expected @@ -1,4 +1,5 @@ failures +testFailures | string_flow.rb:85:10:85:10 | a | Unexpected result: hasValueFlow=a | | string_flow.rb:227:10:227:10 | a | Unexpected result: hasValueFlow=a | edges diff --git a/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.ql b/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.ql index 0c4597b8f07..dfd6242a414 100644 --- a/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.ql +++ b/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.ql @@ -4,8 +4,9 @@ import codeql.ruby.AST import TestUtilities.InlineFlowTest +import DefaultFlowTest import PathGraph -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf -where conf.hasFlowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected b/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected index eb990f9ab27..0597947595a 100644 --- a/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected +++ b/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected @@ -1,4 +1,5 @@ failures +testFailures edges | summaries.rb:1:1:1:7 | tainted | summaries.rb:2:6:2:12 | tainted | | summaries.rb:1:1:1:7 | tainted | summaries.rb:2:6:2:12 | tainted | diff --git a/ruby/ql/test/library-tests/dataflow/summaries/Summaries.ql b/ruby/ql/test/library-tests/dataflow/summaries/Summaries.ql index b59862d0e5a..11145ed991c 100644 --- a/ruby/ql/test/library-tests/dataflow/summaries/Summaries.ql +++ b/ruby/ql/test/library-tests/dataflow/summaries/Summaries.ql @@ -10,7 +10,7 @@ import codeql.ruby.dataflow.internal.FlowSummaryImpl import codeql.ruby.dataflow.internal.AccessPathSyntax import codeql.ruby.frameworks.data.ModelsAsData import TestUtilities.InlineFlowTest -import DataFlow::PathGraph +import PathGraph query predicate invalidSpecComponent(SummarizedCallable sc, string s, string c) { (sc.propagatesFlowExt(s, _, _) or sc.propagatesFlowExt(_, s, _)) and @@ -149,22 +149,18 @@ private class SinkFromModel extends ModelInput::SinkModelCsv { } } -class CustomValueSink extends DefaultValueFlowConf { - override predicate isSink(DataFlow::Node sink) { - super.isSink(sink) +module CustomConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { DefaultFlowConfig::isSource(source) } + + predicate isSink(DataFlow::Node sink) { + DefaultFlowConfig::isSink(sink) or sink = ModelOutput::getASinkNode("test-sink").asSink() } } -class CustomTaintSink extends DefaultTaintFlowConf { - override predicate isSink(DataFlow::Node sink) { - super.isSink(sink) - or - sink = ModelOutput::getASinkNode("test-sink").asSink() - } -} +import FlowTest -from DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Configuration conf -where conf.hasFlowPath(source, sink) +from PathNode source, PathNode sink +where flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.expected b/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.expected index 2fb3829dd40..d9b6f59f4af 100644 --- a/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.expected +++ b/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.expected @@ -1,4 +1,5 @@ failures +testFailures | filter_flow.rb:21:10:21:13 | @foo | Unexpected result: hasTaintFlow= | | filter_flow.rb:38:10:38:13 | @foo | Unexpected result: hasTaintFlow= | | filter_flow.rb:55:10:55:13 | @foo | Unexpected result: hasTaintFlow= | diff --git a/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.ql b/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.ql index 412ba5534b8..1e4e66c5584 100644 --- a/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.ql +++ b/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.ql @@ -7,12 +7,14 @@ import TestUtilities.InlineFlowTest import PathGraph import codeql.ruby.frameworks.Rails -class ParamsTaintFlowConf extends DefaultTaintFlowConf { - override predicate isSource(DataFlow::Node n) { - n.asExpr().getExpr() instanceof Rails::ParamsCall - } +module ParamsTaintFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { n.asExpr().getExpr() instanceof Rails::ParamsCall } + + predicate isSink(DataFlow::Node n) { DefaultFlowConfig::isSink(n) } } -from DataFlow::PathNode source, DataFlow::PathNode sink, ParamsTaintFlowConf conf -where conf.hasFlowPath(source, sink) +import FlowTest + +from TaintFlow::PathNode source, TaintFlow::PathNode sink +where TaintFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/frameworks/action_mailer/params-flow.expected b/ruby/ql/test/library-tests/frameworks/action_mailer/params-flow.expected index 39a6a7b8d8e..11ff425927b 100644 --- a/ruby/ql/test/library-tests/frameworks/action_mailer/params-flow.expected +++ b/ruby/ql/test/library-tests/frameworks/action_mailer/params-flow.expected @@ -1,4 +1,5 @@ failures +testFailures edges | mailer.rb:3:10:3:15 | call to params | mailer.rb:3:10:3:21 | ...[...] | nodes diff --git a/ruby/ql/test/library-tests/frameworks/action_mailer/params-flow.ql b/ruby/ql/test/library-tests/frameworks/action_mailer/params-flow.ql index 412ba5534b8..1e4e66c5584 100644 --- a/ruby/ql/test/library-tests/frameworks/action_mailer/params-flow.ql +++ b/ruby/ql/test/library-tests/frameworks/action_mailer/params-flow.ql @@ -7,12 +7,14 @@ import TestUtilities.InlineFlowTest import PathGraph import codeql.ruby.frameworks.Rails -class ParamsTaintFlowConf extends DefaultTaintFlowConf { - override predicate isSource(DataFlow::Node n) { - n.asExpr().getExpr() instanceof Rails::ParamsCall - } +module ParamsTaintFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { n.asExpr().getExpr() instanceof Rails::ParamsCall } + + predicate isSink(DataFlow::Node n) { DefaultFlowConfig::isSink(n) } } -from DataFlow::PathNode source, DataFlow::PathNode sink, ParamsTaintFlowConf conf -where conf.hasFlowPath(source, sink) +import FlowTest + +from TaintFlow::PathNode source, TaintFlow::PathNode sink +where TaintFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.expected b/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.expected index 7bce95e2b45..7f1f8d6c756 100644 --- a/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.expected +++ b/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.expected @@ -1,4 +1,5 @@ failures +testFailures | hash_extensions.rb:126:10:126:19 | call to sole | Unexpected result: hasValueFlow=b | edges | active_support.rb:10:5:10:5 | x | active_support.rb:11:10:11:10 | x | diff --git a/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.ql b/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.ql index 8a14d5f686e..7c19d2e3904 100644 --- a/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.ql +++ b/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.ql @@ -5,8 +5,9 @@ import codeql.ruby.AST import TestUtilities.InlineFlowTest import codeql.ruby.Frameworks +import DefaultFlowTest import PathGraph -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultValueFlowConf conf -where conf.hasFlowPath(source, sink) +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/frameworks/arel/Arel.expected b/ruby/ql/test/library-tests/frameworks/arel/Arel.expected index d34ccbcb1a1..4fdc2574ccc 100644 --- a/ruby/ql/test/library-tests/frameworks/arel/Arel.expected +++ b/ruby/ql/test/library-tests/frameworks/arel/Arel.expected @@ -1,3 +1,4 @@ failures +testFailures #select | arel.rb:3:8:3:18 | call to sql | arel.rb:2:7:2:14 | call to source | arel.rb:3:8:3:18 | call to sql | $@ | arel.rb:2:7:2:14 | call to source | call to source | diff --git a/ruby/ql/test/library-tests/frameworks/arel/Arel.ql b/ruby/ql/test/library-tests/frameworks/arel/Arel.ql index 01d7b5a5d1c..e1cc2782ceb 100644 --- a/ruby/ql/test/library-tests/frameworks/arel/Arel.ql +++ b/ruby/ql/test/library-tests/frameworks/arel/Arel.ql @@ -5,7 +5,8 @@ import codeql.ruby.frameworks.Arel import codeql.ruby.AST import TestUtilities.InlineFlowTest +import DefaultFlowTest -from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultTaintFlowConf conf -where conf.hasFlowPath(source, sink) +from TaintFlow::PathNode source, TaintFlow::PathNode sink +where TaintFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/frameworks/json/JsonDataFlow.expected b/ruby/ql/test/library-tests/frameworks/json/JsonDataFlow.expected index db04aefd22f..ad5802c2aae 100644 --- a/ruby/ql/test/library-tests/frameworks/json/JsonDataFlow.expected +++ b/ruby/ql/test/library-tests/frameworks/json/JsonDataFlow.expected @@ -1,4 +1,5 @@ failures +testFailures edges | json.rb:1:17:1:26 | call to source | json.rb:1:6:1:27 | call to parse | | json.rb:2:18:2:27 | call to source | json.rb:2:6:2:28 | call to parse! | diff --git a/ruby/ql/test/library-tests/frameworks/json/JsonDataFlow.ql b/ruby/ql/test/library-tests/frameworks/json/JsonDataFlow.ql index 11a25d33e71..6fe0aeda9b1 100644 --- a/ruby/ql/test/library-tests/frameworks/json/JsonDataFlow.ql +++ b/ruby/ql/test/library-tests/frameworks/json/JsonDataFlow.ql @@ -4,4 +4,5 @@ import TestUtilities.InlineFlowTest import codeql.ruby.Frameworks +import DefaultFlowTest import PathGraph diff --git a/ruby/ql/test/library-tests/frameworks/sinatra/Flow.expected b/ruby/ql/test/library-tests/frameworks/sinatra/Flow.expected index 2ace7832268..a2ea0e9a06e 100644 --- a/ruby/ql/test/library-tests/frameworks/sinatra/Flow.expected +++ b/ruby/ql/test/library-tests/frameworks/sinatra/Flow.expected @@ -1,4 +1,5 @@ failures +testFailures | views/index.erb:2:10:2:12 | call to foo | Unexpected result: hasTaintFlow= | edges | app.rb:75:5:75:8 | [post] self [@foo] | app.rb:76:32:76:35 | self [@foo] | diff --git a/ruby/ql/test/library-tests/frameworks/sinatra/Flow.ql b/ruby/ql/test/library-tests/frameworks/sinatra/Flow.ql index d54f73c9144..413511eac08 100644 --- a/ruby/ql/test/library-tests/frameworks/sinatra/Flow.ql +++ b/ruby/ql/test/library-tests/frameworks/sinatra/Flow.ql @@ -8,12 +8,16 @@ import PathGraph import codeql.ruby.frameworks.Sinatra import codeql.ruby.Concepts -class SinatraConf extends DefaultTaintFlowConf { - override predicate isSource(DataFlow::Node source) { +module SinatraConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Http::Server::RequestInputAccess::Range } + + predicate isSink(DataFlow::Node sink) { DefaultFlowConfig::isSink(sink) } } -from DataFlow::PathNode source, DataFlow::PathNode sink, SinatraConf conf -where conf.hasFlowPath(source, sink) +import FlowTest + +from TaintFlow::PathNode source, TaintFlow::PathNode sink +where TaintFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/query-tests/security/cwe-829/InsecureDownload.expected b/ruby/ql/test/query-tests/security/cwe-829/InsecureDownload.expected index 6e30aeeb235..82fbafcfc89 100644 --- a/ruby/ql/test/query-tests/security/cwe-829/InsecureDownload.expected +++ b/ruby/ql/test/query-tests/security/cwe-829/InsecureDownload.expected @@ -18,6 +18,7 @@ nodes | insecure_download.rb:43:22:43:56 | "http://example.org/unsafe.unk..." | semmle.label | "http://example.org/unsafe.unk..." | | insecure_download.rb:53:65:53:78 | "/myscript.sh" | semmle.label | "/myscript.sh" | subpaths +testFailures #select | insecure_download.rb:27:15:27:45 | "http://example.org/unsafe.APK" | insecure_download.rb:27:15:27:45 | "http://example.org/unsafe.APK" | insecure_download.rb:27:15:27:45 | "http://example.org/unsafe.APK" | $@ | insecure_download.rb:27:15:27:45 | "http://example.org/unsafe.APK" | "http://example.org/unsafe.APK" | | insecure_download.rb:27:15:27:45 | "http://example.org/unsafe.APK" | insecure_download.rb:27:15:27:45 | "http://example.org/unsafe.APK" | insecure_download.rb:27:15:27:45 | "http://example.org/unsafe.APK" | $@ | insecure_download.rb:27:15:27:45 | "http://example.org/unsafe.APK" | "http://example.org/unsafe.APK" | diff --git a/ruby/ql/test/query-tests/security/cwe-829/InsecureDownload.ql b/ruby/ql/test/query-tests/security/cwe-829/InsecureDownload.ql index 8690a0ec120..ab9ce62a21c 100644 --- a/ruby/ql/test/query-tests/security/cwe-829/InsecureDownload.ql +++ b/ruby/ql/test/query-tests/security/cwe-829/InsecureDownload.ql @@ -1,22 +1,25 @@ import codeql.ruby.AST import codeql.ruby.DataFlow -import PathGraph -import TestUtilities.InlineFlowTest import codeql.ruby.security.InsecureDownloadQuery +import Flow::PathGraph +import TestUtilities.InlineExpectationsTest +import TestUtilities.InlineFlowTestUtil -class FlowTest extends InlineFlowTest { - override DataFlow::Configuration getValueFlowConfig() { result = any(Configuration config) } +module FlowTest implements TestSig { + string getARelevantTag() { result = "BAD" } - override DataFlow::Configuration getTaintFlowConfig() { none() } - - override string getARelevantTag() { result = "BAD" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { tag = "BAD" and - super.hasActualResult(location, element, "hasValueFlow", value) + exists(DataFlow::Node src, DataFlow::Node sink | Flow::flow(src, sink) | + sink.getLocation() = location and + element = sink.toString() and + if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = "" + ) } } -from DataFlow::PathNode source, DataFlow::PathNode sink, Configuration conf -where conf.hasFlowPath(source, sink) +import MakeTest + +from Flow::PathNode source, Flow::PathNode sink +where Flow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() From 91b2de2b612d403c2b411f9bf407e75ae422fbf5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 15 Jun 2023 08:50:57 +0100 Subject: [PATCH 130/364] Swift: Lots of small fixes / cleanup. --- swift/ql/lib/codeql/swift/regex/Regex.qll | 10 +++--- .../lib/codeql/swift/regex/RegexTreeView.qll | 2 +- .../library-tests/regex/redos_variants.swift | 34 +++++++++---------- .../ANodeBlog-LICENSE | 0 .../CodeMirror-LICENSE | 0 .../Prism-LICENSE | 0 .../Prototype.js-LICENSE | 0 .../brace-expansion-LICENSE | 0 .../jest-LICENSE | 0 .../knockout-LICENSE | 0 .../marked-LICENSE | 0 .../regex/test_the_tests.swift.disabled | 25 ++++++++------ 12 files changed, 36 insertions(+), 35 deletions(-) rename swift/ql/test/library-tests/regex/{licenses => test_fragment_licenses}/ANodeBlog-LICENSE (100%) rename swift/ql/test/library-tests/regex/{licenses => test_fragment_licenses}/CodeMirror-LICENSE (100%) rename swift/ql/test/library-tests/regex/{licenses => test_fragment_licenses}/Prism-LICENSE (100%) rename swift/ql/test/library-tests/regex/{licenses => test_fragment_licenses}/Prototype.js-LICENSE (100%) rename swift/ql/test/library-tests/regex/{licenses => test_fragment_licenses}/brace-expansion-LICENSE (100%) rename swift/ql/test/library-tests/regex/{licenses => test_fragment_licenses}/jest-LICENSE (100%) rename swift/ql/test/library-tests/regex/{licenses => test_fragment_licenses}/knockout-LICENSE (100%) rename swift/ql/test/library-tests/regex/{licenses => test_fragment_licenses}/marked-LICENSE (100%) diff --git a/swift/ql/lib/codeql/swift/regex/Regex.qll b/swift/ql/lib/codeql/swift/regex/Regex.qll index bad4baa2c16..e92a7a25114 100644 --- a/swift/ql/lib/codeql/swift/regex/Regex.qll +++ b/swift/ql/lib/codeql/swift/regex/Regex.qll @@ -3,8 +3,8 @@ */ import swift -import codeql.swift.dataflow.DataFlow -import codeql.swift.regex.RegexTreeView // re-export +import codeql.swift.regex.RegexTreeView +private import codeql.swift.dataflow.DataFlow private import internal.ParseRegex /** @@ -54,7 +54,7 @@ private class ParsedStringRegex extends RegExp, StringLiteralExpr { } /** - * A call that evaluates a regular expression. For example: + * A call that evaluates a regular expression. For example, the call to `firstMatch` in: * ``` * Regex("(a|b).*").firstMatch(in: myString) * ``` @@ -64,7 +64,7 @@ abstract class RegexEval extends CallExpr { Expr stringInput; /** - * Gets the input to this call that is the regular expression. + * Gets the input to this call that is the regular expression being evaluated. */ Expr getRegexInput() { result = regexInput } @@ -76,7 +76,7 @@ abstract class RegexEval extends CallExpr { /** * Gets a regular expression value that is evaluated here (if any can be identified). */ - RegExp getARegex() { exists(ParsedStringRegex regex | regex.getEval() = this and result = regex) } + RegExp getARegex() { result.(ParsedStringRegex).getEval() = this } } /** diff --git a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll index bc401cc1698..6970342f213 100644 --- a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll +++ b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll @@ -661,7 +661,7 @@ private module Impl implements RegexTreeViewSig { * * Examples: * - * ```rb + * ``` * /[a-fA-F0-9]/ * /[^abc]/ * ``` diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index ea63005c495..1fb56befb82 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -150,7 +150,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex(#"([\w.]+)*"#).firstMatch(in: tainted) // BAD // attack string: "a" x lots + "!" - _ = try Regex(#"([\w.]+)*"#).wholeMatch(in: tainted) + _ = try Regex(#"([\w.]+)*"#).wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= // BAD // attack string: "b" x lots + "!" @@ -264,13 +264,13 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex(#"(\d+(X\d+)?)+"#).firstMatch(in: tainted) // BAD // attack string: "0" x lots + "!" - _ = try Regex(#"(\d+(X\d+)?)+"#).wholeMatch(in: tainted) + _ = try Regex(#"(\d+(X\d+)?)+"#).wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD - there is no witness in the end that could cause the regexp to not match _ = try Regex("([0-9]+(X[0-9]*)?)*").firstMatch(in: tainted) // BAD // attack string: "0" x lots + "!" - _ = try Regex("([0-9]+(X[0-9]*)?)*").wholeMatch(in: tainted) + _ = try Regex("([0-9]+(X[0-9]*)?)*").wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD _ = try Regex("^([^>]+)*(>|$)").firstMatch(in: tainted) @@ -307,7 +307,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("(a+)+aaaaa*a+").firstMatch(in: tainted) // BAD // attack string: "a" x lots + "!" - _ = try Regex("(a+)+aaaaa*a+").wholeMatch(in: tainted) + _ = try Regex("(a+)+aaaaa*a+").wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= // BAD // attack string: "a" x lots + "!" @@ -317,7 +317,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex(#"(\n+)+\n\n"#).firstMatch(in: tainted) // BAD // attack string: "\n" x lots + "." - _ = try Regex(#"(\n+)+\n\n"#).wholeMatch(in: tainted) + _ = try Regex(#"(\n+)+\n\n"#).wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= // BAD // attack string: "\n" x lots + "." @@ -335,7 +335,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("(([^X]b)+)*($|[^X]b)").firstMatch(in: tainted) // BAD // attack string: "b" x lots + "!" - _ = try Regex("(([^X]b)+)*($|[^X]b)").wholeMatch(in: tainted) + _ = try Regex("(([^X]b)+)*($|[^X]b)").wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= // BAD // attack string: "b" x lots + "!" @@ -345,19 +345,19 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex("((ab)+)*ababab").firstMatch(in: tainted) // BAD // attack string: "ab" x lots + "!" - _ = try Regex("((ab)+)*ababab").wholeMatch(in: tainted) + _ = try Regex("((ab)+)*ababab").wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD _ = try Regex("((ab)+)*abab(ab)*(ab)+").firstMatch(in: tainted) // BAD // attack string: "ab" x lots + "!" - _ = try Regex("((ab)+)*abab(ab)*(ab)+").wholeMatch(in: tainted) + _ = try Regex("((ab)+)*abab(ab)*(ab)+").wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD _ = try Regex("((ab)+)*").firstMatch(in: tainted) // BAD // attack string: "ab" x lots + "!" - _ = try Regex("((ab)+)*").wholeMatch(in: tainted) + _ = try Regex("((ab)+)*").wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= // BAD // attack string: "ab" x lots + "!" @@ -480,17 +480,15 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex("(a|b)+").firstMatch(in: tainted) - // BAD + // GOOD _ = try Regex(#"(?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]))+"#).firstMatch(in: tainted) - // BAD - // attack string: ??? - _ = try Regex(#"(?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]))+"#).wholeMatch(in: tainted) - // TODO: investigate; these were marked `hasParseFailure` - _ = try Regex(#"^((?:a{|-)|\w\{)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= - _ = try Regex(#"^((?:a{0|-)|\w\{\d)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= - _ = try Regex(#"^((?:a{0,|-)|\w\{\d,)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= - _ = try Regex(#"^((?:a{0,2|-)|\w\{\d,\d)+X$"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + // BAD? + // (no confirmed attack string) + _ = try Regex(#"^((?:a{|-)|\w\{)+X$"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^((?:a{0|-)|\w\{\d)+X$"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^((?:a{0,|-)|\w\{\d,)+X$"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^((?:a{0,2|-)|\w\{\d,\d)+X$"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"^((?:a{0,2}|-)|\w\{\d,\d\})+X$"#).firstMatch(in: tainted) diff --git a/swift/ql/test/library-tests/regex/licenses/ANodeBlog-LICENSE b/swift/ql/test/library-tests/regex/test_fragment_licenses/ANodeBlog-LICENSE similarity index 100% rename from swift/ql/test/library-tests/regex/licenses/ANodeBlog-LICENSE rename to swift/ql/test/library-tests/regex/test_fragment_licenses/ANodeBlog-LICENSE diff --git a/swift/ql/test/library-tests/regex/licenses/CodeMirror-LICENSE b/swift/ql/test/library-tests/regex/test_fragment_licenses/CodeMirror-LICENSE similarity index 100% rename from swift/ql/test/library-tests/regex/licenses/CodeMirror-LICENSE rename to swift/ql/test/library-tests/regex/test_fragment_licenses/CodeMirror-LICENSE diff --git a/swift/ql/test/library-tests/regex/licenses/Prism-LICENSE b/swift/ql/test/library-tests/regex/test_fragment_licenses/Prism-LICENSE similarity index 100% rename from swift/ql/test/library-tests/regex/licenses/Prism-LICENSE rename to swift/ql/test/library-tests/regex/test_fragment_licenses/Prism-LICENSE diff --git a/swift/ql/test/library-tests/regex/licenses/Prototype.js-LICENSE b/swift/ql/test/library-tests/regex/test_fragment_licenses/Prototype.js-LICENSE similarity index 100% rename from swift/ql/test/library-tests/regex/licenses/Prototype.js-LICENSE rename to swift/ql/test/library-tests/regex/test_fragment_licenses/Prototype.js-LICENSE diff --git a/swift/ql/test/library-tests/regex/licenses/brace-expansion-LICENSE b/swift/ql/test/library-tests/regex/test_fragment_licenses/brace-expansion-LICENSE similarity index 100% rename from swift/ql/test/library-tests/regex/licenses/brace-expansion-LICENSE rename to swift/ql/test/library-tests/regex/test_fragment_licenses/brace-expansion-LICENSE diff --git a/swift/ql/test/library-tests/regex/licenses/jest-LICENSE b/swift/ql/test/library-tests/regex/test_fragment_licenses/jest-LICENSE similarity index 100% rename from swift/ql/test/library-tests/regex/licenses/jest-LICENSE rename to swift/ql/test/library-tests/regex/test_fragment_licenses/jest-LICENSE diff --git a/swift/ql/test/library-tests/regex/licenses/knockout-LICENSE b/swift/ql/test/library-tests/regex/test_fragment_licenses/knockout-LICENSE similarity index 100% rename from swift/ql/test/library-tests/regex/licenses/knockout-LICENSE rename to swift/ql/test/library-tests/regex/test_fragment_licenses/knockout-LICENSE diff --git a/swift/ql/test/library-tests/regex/licenses/marked-LICENSE b/swift/ql/test/library-tests/regex/test_fragment_licenses/marked-LICENSE similarity index 100% rename from swift/ql/test/library-tests/regex/licenses/marked-LICENSE rename to swift/ql/test/library-tests/regex/test_fragment_licenses/marked-LICENSE diff --git a/swift/ql/test/library-tests/regex/test_the_tests.swift.disabled b/swift/ql/test/library-tests/regex/test_the_tests.swift.disabled index 00a062a5dca..d7ffbc6ef05 100644 --- a/swift/ql/test/library-tests/regex/test_the_tests.swift.disabled +++ b/swift/ql/test/library-tests/regex/test_the_tests.swift.disabled @@ -1,10 +1,11 @@ -// This program tests the regular expressions from the tests to (hopefully) figure out which ones -// are really vulnerable to various attack strings in Swift. And confirm they are valid Swift -// regular expressions in the first place. +// This program tests the regular expressions from the tests to figure out which ones are really +// vulnerable to various attack strings with the Swift `Regex` implementation. We also confirm +// all really are valid Swift regular expressions. // -// It works by searching the source file for regular expressions in a particular form -// (roughly `Regex("...")`). A slight catch is that it doesn't process escape characters in the -// way Swift does, so it's best not to use them (use Swift #""# strings to avoid needing them). +// The program works by searching the test source file (or part of it) for regular expressions in +// the form `Regex("...")` or `Regex(#"..."#)`. A drawback of this approach is that it doesn't +// process escape characters in the way Swift does, so it's best not to use them in non-trivial +// test cases (use Swift #""# strings to avoid needing escape sequences). import Foundation @@ -85,19 +86,19 @@ print() var tests: [TestCase] = [] -let lineRegex = try Regex(".*Regex\\(#*\"(.*)\"#*\\).*") // only matches `Regex("...")` +let lineRegex = try Regex(".*Regex\\(#*\"(.*)\"#*\\).*") // matches `Regex("...")`, `Regex(#"..."#)` etc. // read source file, process it line by line... let wholeFile = try String(contentsOfFile: "redos_variants.swift") var lines = wholeFile.components(separatedBy: .newlines) -// filter lines (the whole thing is a lot) +// filter lines (running more than a few thousand test cases at once is not recommended) lines = Array(lines[1 ..< 120]) var regexpCount = 0 for line in lines { - // check if the line matches regex... + // check if the line matches the line regex... if let match = try lineRegex.wholeMatch(in: line) { if let regexSubstr = match.output[1].substring { let regexStr = String(regexSubstr) @@ -118,7 +119,9 @@ for line in lines { } } -// run the tests (in parallel)... +// run the tests... +// (in parallel, because each test doesn't necessarily terminate and we have no easy way to force +// them to terminate short of ending the process as a whole) print("\(regexpCount) regular expression(s)") print("\(tests.count) test case(s)") for test in tests { @@ -128,7 +131,7 @@ for test in tests { // wait... Thread.sleep(forTimeInterval: 20.0) -// report those still running +// report those cases that are still running print("incomplete after 20 seconds:") for test in tests { if test.done == false { From 4a06394d51a6dc14d976af1a86ad3c5bb7bed2e5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 15 Jun 2023 13:08:33 +0100 Subject: [PATCH 131/364] Swift: Autoformat + fix test indentation. --- .../lib/codeql/swift/regex/RegexTreeView.qll | 35 +++++---- .../swift/regex/internal/ParseRegex.qll | 4 +- .../library-tests/regex/redos_variants.swift | 78 +++++++++---------- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll index 6970342f213..3a9738bffec 100644 --- a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll +++ b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll @@ -207,25 +207,30 @@ private module Impl implements RegexTreeViewSig { */ Location getLocation() { result = re.getLocation() } - /*pragma[noinline] - private predicate componentHasLocationInfo( - int i, string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - re.getComponent(i) - .getLocation() - .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - }*/ + /* + * pragma[noinline] + * private predicate componentHasLocationInfo( + * int i, string filepath, int startline, int startcolumn, int endline, int endcolumn + * ) { + * re.getComponent(i) + * .getLocation() + * .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + * } + */ /** Holds if this term is found at the specified location offsets. */ predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - /*exists(int re_start | - this.componentHasLocationInfo(0, filepath, startline, re_start, _, _) and - this.componentHasLocationInfo(re.getNumberOfComponents() - 1, filepath, _, _, endline, _) and - startcolumn = re_start + start and - endcolumn = re_start + end - 1 - )*/ + /* + * exists(int re_start | + * this.componentHasLocationInfo(0, filepath, startline, re_start, _, _) and + * this.componentHasLocationInfo(re.getNumberOfComponents() - 1, filepath, _, _, endline, _) and + * startcolumn = re_start + start and + * endcolumn = re_start + end - 1 + * ) + */ + filepath = re.getFile().getAbsolutePath() and startline = re.getLocation().getStartLine() and startcolumn = re.getLocation().getStartColumn() and @@ -1197,7 +1202,7 @@ private module Impl implements RegexTreeViewSig { * Holds if the regular expression should not be considered. */ predicate isExcluded(RegExpParent parent) { - none()//parent.(RegExpTerm).getRegExp().(Ast::RegExpLiteral).hasFreeSpacingFlag() // exclude free-spacing mode regexes + none() //parent.(RegExpTerm).getRegExp().(Ast::RegExpLiteral).hasFreeSpacingFlag() // exclude free-spacing mode regexes } /** diff --git a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll index 36450bcdfb9..439eab6a17f 100644 --- a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll +++ b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll @@ -255,9 +255,7 @@ abstract class RegExp extends Expr { /** * Gets the text of this regex. */ - string getText() { - result = this.(StringLiteralExpr).getValue() - } + string getText() { result = this.(StringLiteralExpr).getValue() } /** Gets the `i`th character of this regex */ string getChar(int i) { result = this.getText().charAt(i) } diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 1fb56befb82..216bfc2b1c7 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -2,7 +2,7 @@ // --- stubs --- struct URL { - init?(string: String) {} + init?(string: String) {} } struct AnyRegexOutput { @@ -12,20 +12,20 @@ protocol RegexComponent { } struct Regex : RegexComponent { - struct Match { - } + struct Match { + } - init(_ pattern: String) throws where Output == AnyRegexOutput { } + init(_ pattern: String) throws where Output == AnyRegexOutput { } - func firstMatch(in string: String) throws -> Regex.Match? { return nil} - func prefixMatch(in string: String) throws -> Regex.Match? { return nil} - func wholeMatch(in string: String) throws -> Regex.Match? { return nil} + func firstMatch(in string: String) throws -> Regex.Match? { return nil} + func prefixMatch(in string: String) throws -> Regex.Match? { return nil} + func wholeMatch(in string: String) throws -> Regex.Match? { return nil} - typealias RegexOutput = Output + typealias RegexOutput = Output } extension String { - init(contentsOf: URL) { + init(contentsOf: URL) { let data = "" self.init(data) } @@ -36,88 +36,88 @@ extension String { // the focus for these tests is different vulnerable and non-vulnerable regexp strings. func myRegexpVariantsTests(myUrl: URL) throws { - let tainted = String(contentsOf: myUrl) // tainted + let tainted = String(contentsOf: myUrl) // tainted // basic cases: // attack string: "a" x lots + "!" - _ = try Regex(".*").firstMatch(in: tainted) // $ regex=.* input=tainted + _ = try Regex(".*").firstMatch(in: tainted) // $ regex=.* input=tainted - _ = try Regex("a*b").firstMatch(in: tainted) // $ regex=a*b input=tainted - _ = try Regex("(a*)b").firstMatch(in: tainted) // $ regex=(a*)b input=tainted - _ = try Regex("(a)*b").firstMatch(in: tainted) // $ regex=(a)*b input=tainted - _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ regex=(a*)*b input=tainted redos-vulnerable= - _ = try Regex("((a*)*b)").firstMatch(in: tainted) // $ regex=((a*)*b) input=tainted redos-vulnerable= + _ = try Regex("a*b").firstMatch(in: tainted) // $ regex=a*b input=tainted + _ = try Regex("(a*)b").firstMatch(in: tainted) // $ regex=(a*)b input=tainted + _ = try Regex("(a)*b").firstMatch(in: tainted) // $ regex=(a)*b input=tainted + _ = try Regex("(a*)*b").firstMatch(in: tainted) // $ regex=(a*)*b input=tainted redos-vulnerable= + _ = try Regex("((a*)*b)").firstMatch(in: tainted) // $ regex=((a*)*b) input=tainted redos-vulnerable= - _ = try Regex("(a|aa?)b").firstMatch(in: tainted) // $ regex=(a|aa?)b input=tainted - _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex=(a|aa?)*b input=tainted redos-vulnerable= + _ = try Regex("(a|aa?)b").firstMatch(in: tainted) // $ regex=(a|aa?)b input=tainted + _ = try Regex("(a|aa?)*b").firstMatch(in: tainted) // $ regex=(a|aa?)*b input=tainted redos-vulnerable= // from the qhelp: - // attack string: "_" x lots + "!" + // attack string: "_" x lots + "!" - _ = try Regex("^_(__|.)+_$").firstMatch(in: tainted) // $ regex=^_(__|.)+_$ input=tainted redos-vulnerable= - _ = try Regex("^_(__|[^_])+_$").firstMatch(in: tainted) // $ regex=^_(__|[^_])+_$ input=tainted + _ = try Regex("^_(__|.)+_$").firstMatch(in: tainted) // $ regex=^_(__|.)+_$ input=tainted redos-vulnerable= + _ = try Regex("^_(__|[^_])+_$").firstMatch(in: tainted) // $ regex=^_(__|[^_])+_$ input=tainted // real world cases: // Adapted from marked (https://github.com/markedjs/marked), which is licensed // under the MIT license; see file licenses/marked-LICENSE. // GOOD - _ = try Regex(#"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= - // BAD + _ = try Regex(#"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"#).firstMatch(in: tainted) // $ SPURIOUS: redos-vulnerable= + // BAD // attack string: "_" + "__".repeat(100) - _ = try Regex(#"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"#).wholeMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"#).wholeMatch(in: tainted) // $ redos-vulnerable= // GOOD // Adapted from marked (https://github.com/markedjs/marked), which is licensed // under the MIT license; see file licenses/marked-LICENSE. - _ = try Regex(#"^\b_((?:__|[^_])+?)_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)"#).firstMatch(in: tainted) + _ = try Regex(#"^\b_((?:__|[^_])+?)_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)"#).firstMatch(in: tainted) // GOOD - there is no witness in the end that could cause the regexp to not match // Adapted from brace-expansion (https://github.com/juliangruber/brace-expansion), // which is licensed under the MIT license; see file licenses/brace-expansion-LICENSE. - _ = try Regex("(.*,)+.+").firstMatch(in: tainted) + _ = try Regex("(.*,)+.+").firstMatch(in: tainted) // BAD // attack string: " '" + "\\\\".repeat(100) // Adapted from CodeMirror (https://github.com/codemirror/codemirror), // which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE. - _ = try Regex(#"^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD // Adapted from jest (https://github.com/facebook/jest), which is licensed // under the MIT license; see file licenses/jest-LICENSE. - _ = try Regex(#"^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*"#).firstMatch(in: tainted) + _ = try Regex(#"^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*"#).firstMatch(in: tainted) // BAD // attack string: "/" + "\\/a".repeat(100) // Adapted from ANodeBlog (https://github.com/gefangshuai/ANodeBlog), // which is licensed under the Apache License 2.0; see file licenses/ANodeBlog-LICENSE. - _ = try Regex(#"\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)"#).firstMatch(in: tainted) // $ redos-vulnerable= // BAD // attack string: "##".repeat(100) + "\na" // Adapted from CodeMirror (https://github.com/codemirror/codemirror), // which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE. - _ = try Regex(#"^([\s\[\{\(]|#.*)*$"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^([\s\[\{\(]|#.*)*$"#).firstMatch(in: tainted) // $ redos-vulnerable= // BAD // attack string: "a" + "[]".repeat(100) + ".b\n" // Adapted from Knockout (https://github.com/knockout/knockout), which is // licensed under the MIT license; see file licenses/knockout-LICENSE - _ = try Regex(#"^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$"#).firstMatch(in: tainted) // $ redos-vulnerable= // BAD // attack string: "[" + "][".repeat(100) + "]!" // Adapted from Prototype.js (https://github.com/prototypejs/prototype), which // is licensed under the MIT license; see file licenses/Prototype.js-LICENSE. - _ = try Regex(#"(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)"#).firstMatch(in: tainted) // $ redos-vulnerable= // BAD // attack string: "'" + "\\a".repeat(100) + '"' // Adapted from Prism (https://github.com/PrismJS/prism), which is licensed // under the MIT license; see file licenses/Prism-LICENSE. - _ = try Regex(#"("|')(\\?.)*?\1"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"("|')(\\?.)*?\1"#).firstMatch(in: tainted) // $ redos-vulnerable= // more cases: @@ -148,7 +148,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex(#"([\w.]+)*"#).firstMatch(in: tainted) - // BAD + // BAD // attack string: "a" x lots + "!" _ = try Regex(#"([\w.]+)*"#).wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= @@ -214,7 +214,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { // BAD // attack string: "5" x lots + "!" - _ = try Regex(#"((\d|\d)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"((\d|\d)*)""#).firstMatch(in: tainted) // $ redos-vulnerable= // BAD // attack string: "0" x lots + "!" @@ -262,7 +262,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD - there is no witness in the end that could cause the regexp to not match _ = try Regex(#"(\d+(X\d+)?)+"#).firstMatch(in: tainted) - // BAD + // BAD // attack string: "0" x lots + "!" _ = try Regex(#"(\d+(X\d+)?)+"#).wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= @@ -305,7 +305,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex("(a+)+aaaaa*a+").firstMatch(in: tainted) - // BAD + // BAD // attack string: "a" x lots + "!" _ = try Regex("(a+)+aaaaa*a+").wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= @@ -333,7 +333,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex("(([^X]b)+)*($|[^X]b)").firstMatch(in: tainted) - // BAD + // BAD // attack string: "b" x lots + "!" _ = try Regex("(([^X]b)+)*($|[^X]b)").wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= @@ -544,7 +544,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex(#"("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)"#).firstMatch(in: tainted) - // BAD + // BAD // attack string: "##" x lots + "\na" _ = try Regex(#"("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)"#).wholeMatch(in: tainted) // $ MISSING: redos-vulnerable= From 21b55ce0cf9b1c128c010459f5ebb8739b4b42eb Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Thu, 15 Jun 2023 12:49:02 +0200 Subject: [PATCH 132/364] stop spuriously matching everything when encountering an unsupported charclass --- shared/regex/codeql/regex/nfa/NfaUtils.qll | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/shared/regex/codeql/regex/nfa/NfaUtils.qll b/shared/regex/codeql/regex/nfa/NfaUtils.qll index 3fd4b97c829..5bad1e80727 100644 --- a/shared/regex/codeql/regex/nfa/NfaUtils.qll +++ b/shared/regex/codeql/regex/nfa/NfaUtils.qll @@ -451,7 +451,15 @@ module Make { } bindingset[char] - override predicate matches(string char) { not hasChildThatMatches(cc, char) } + override predicate matches(string char) { + not hasChildThatMatches(cc, char) and + ( + // detect unsupported char classes that doesn't match anything (e.g. `\p{L}` in ruby), and don't report any matches + exists(string c | hasChildThatMatches(cc, c)) + or + not exists(cc.getAChild()) // [^] still matches everything + ) + } } /** @@ -536,7 +544,9 @@ module Make { bindingset[char] override predicate matches(string char) { - not classEscapeMatches(charClass.toLowerCase(), char) + not classEscapeMatches(charClass.toLowerCase(), char) and + // detect unsupported char classes (e.g. `\p{L}` in ruby), and don't report any matches + exists(string c | classEscapeMatches(charClass.toLowerCase(), c)) } } From 087e6d1c15e174c83b7f6bcd0c53cf8cf0546f81 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Thu, 15 Jun 2023 13:52:29 +0200 Subject: [PATCH 133/364] fix QL-for-QL warning --- shared/regex/codeql/regex/nfa/NfaUtils.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/regex/codeql/regex/nfa/NfaUtils.qll b/shared/regex/codeql/regex/nfa/NfaUtils.qll index 5bad1e80727..b690bfdd5e9 100644 --- a/shared/regex/codeql/regex/nfa/NfaUtils.qll +++ b/shared/regex/codeql/regex/nfa/NfaUtils.qll @@ -455,7 +455,7 @@ module Make { not hasChildThatMatches(cc, char) and ( // detect unsupported char classes that doesn't match anything (e.g. `\p{L}` in ruby), and don't report any matches - exists(string c | hasChildThatMatches(cc, c)) + hasChildThatMatches(cc, _) or not exists(cc.getAChild()) // [^] still matches everything ) @@ -546,7 +546,7 @@ module Make { override predicate matches(string char) { not classEscapeMatches(charClass.toLowerCase(), char) and // detect unsupported char classes (e.g. `\p{L}` in ruby), and don't report any matches - exists(string c | classEscapeMatches(charClass.toLowerCase(), c)) + classEscapeMatches(charClass.toLowerCase(), _) } } From 9e9ef42054ec93ba08a00fac42215ff342535b91 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 15 Jun 2023 13:25:02 +0100 Subject: [PATCH 134/364] Swift: Add another test case. --- swift/ql/test/library-tests/regex/regex.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/swift/ql/test/library-tests/regex/regex.swift b/swift/ql/test/library-tests/regex/regex.swift index badf568720b..fbe52ba6fa4 100644 --- a/swift/ql/test/library-tests/regex/regex.swift +++ b/swift/ql/test/library-tests/regex/regex.swift @@ -143,8 +143,13 @@ func myRegexpMethodsTests(b: Bool) throws { _ = try either_regex.firstMatch(in: input) // $ regex=.* regex=.+ input=input let base_str = "a" - let append_regex = try Regex(base_str + "b") - _ = try append_regex.firstMatch(in: input) // $ input=input MISSING: regex=ab + let appended_regex = try Regex(base_str + "b") + _ = try appended_regex.firstMatch(in: input) // $ input=input MISSING: regex=ab + + let multiple_evaluated_regex = try Regex(#"([\w.]+)*"#) + try _ = multiple_evaluated_regex.firstMatch(in: input) // $ input=input regex=([\w.]+)* + try _ = multiple_evaluated_regex.prefixMatch(in: input) // $ input=input regex=([\w.]+)* + try _ = multiple_evaluated_regex.wholeMatch(in: input) // $ input=input regex=([\w.]+)* MISSING: redos-vulnerable= // --- escape sequences --- From 9b9b4a1fd77251b8c8665e8cf905e79f78955851 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 15 Jun 2023 14:31:49 +0100 Subject: [PATCH 135/364] Swift: Fix QL-for-QL warnings. --- .../lib/codeql/swift/regex/internal/ParseRegex.qll | 12 ++++++------ swift/ql/test/library-tests/regex/regex.ql | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll index 439eab6a17f..5b88e8b899f 100644 --- a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll +++ b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll @@ -193,9 +193,9 @@ abstract class RegExp extends Expr { } /** - * Holds if the character set starting at `charset_start` contains a character range - * with lower bound found between `start` and `lower_end` - * and upper bound found between `upper_start` and `end`. + * Holds if the character set starting at `charsetStart` contains a character range + * with lower bound found between `start` and `lowerEnd` + * and upper bound found between `upperStart` and `end`. */ predicate charRange(int charsetStart, int start, int lowerEnd, int upperStart, int end) { exists(int index | @@ -841,11 +841,11 @@ abstract class RegExp extends Expr { } /** - * Holds if a qualified part is found between `start` and `part_end` and the qualifier is + * Holds if a qualified part is found between `start` and `partEnd` and the qualifier is * found between `part_end` and `end`. * - * `maybe_empty` is true if the part is optional. - * `may_repeat_forever` is true if the part may be repeated unboundedly. + * `maybeEmpty` is true if the part is optional. + * `mayRepeatForever` is true if the part may be repeated unboundedly. */ predicate qualifiedPart( int start, int partEnd, int end, boolean maybeEmpty, boolean mayRepeatForever diff --git a/swift/ql/test/library-tests/regex/regex.ql b/swift/ql/test/library-tests/regex/regex.ql index 3c8579bff84..f3d0d67f120 100644 --- a/swift/ql/test/library-tests/regex/regex.ql +++ b/swift/ql/test/library-tests/regex/regex.ql @@ -12,8 +12,8 @@ module RegexTest implements TestSig { string getARelevantTag() { result = ["regex", "input", "redos-vulnerable", "hasParseFailure"] } predicate hasActualResult(Location location, string element, string tag, string value) { - exists(TreeView::RegExpTerm t, string pump, State s, string prefixMsg | - hasReDoSResult(t, pump, s, prefixMsg) and + exists(TreeView::RegExpTerm t | + hasReDoSResult(t, _, _, _) and location = t.getLocation() and element = t.toString() and tag = "redos-vulnerable" and From 1b39faadede91de9e810665ff9ed7575fbc768c2 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Thu, 15 Jun 2023 16:20:39 +0200 Subject: [PATCH 136/364] QLDoc correction --- java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll b/java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll index dbccfc99c04..f17090ed307 100644 --- a/java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll +++ b/java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll @@ -99,7 +99,7 @@ private class GenerateResponseMethod extends Method { } } -/** Gets the static type of `e`, or an upper bound of the runtime type of `e`. */ +/** Holds if `t` is the static type of `e`, or an upper bound of the runtime type of `e`. */ private predicate boundOrStaticType(Expr e, RefType t) { exprTypeFlow(e, t, false) or From 3aaa649076d5b7e726452a480588698b62df75a6 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 15 Jun 2023 16:50:42 +0200 Subject: [PATCH 137/364] Exclude `cpp/overrun-write` from `cpp-security-extended.qls` --- cpp/ql/src/codeql-suites/cpp-security-extended.qls | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpp/ql/src/codeql-suites/cpp-security-extended.qls b/cpp/ql/src/codeql-suites/cpp-security-extended.qls index 69c014c4c6f..75deda24ef5 100644 --- a/cpp/ql/src/codeql-suites/cpp-security-extended.qls +++ b/cpp/ql/src/codeql-suites/cpp-security-extended.qls @@ -3,3 +3,6 @@ - apply: security-extended-selectors.yml from: codeql/suite-helpers - apply: codeql-suites/exclude-slow-queries.yml +- exclude: + id: cpp/overrun-write + From 05939bd90aa15ab1796916e0cbf73b67ef92b66d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 15 Jun 2023 20:51:21 +0100 Subject: [PATCH 138/364] Swift: Add a test case for \Uhhhhhhhh character escapes. --- swift/ql/test/library-tests/regex/redos_variants.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 216bfc2b1c7..725157c6970 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -500,6 +500,13 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex(#"X(\u0061|b)+Y"#).firstMatch(in: tainted) + // BAD + // attack string: "X" + "a" x lots + _ = try Regex(#"X(\U00000061|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + + // GOOD + _ = try Regex(#"X(\U00000061|b)+Y"#).firstMatch(in: tainted) + // BAD TODO: we should get this one // attack string: "X" + "a" x lots _ = try Regex(#"X(\x61|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= From 49dfe5d22bf9f0e46bf87692104a9e76f9531bc3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 15 Jun 2023 17:57:44 +0100 Subject: [PATCH 139/364] Swift: Add support for \Uhhhhhhhh escaped characters in regular expressions. --- .../ql/lib/codeql/swift/regex/internal/ParseRegex.qll | 11 ++++++++--- .../ql/test/library-tests/regex/redos_variants.swift | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll index 5b88e8b899f..dfe33630401 100644 --- a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll +++ b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll @@ -320,7 +320,8 @@ abstract class RegExp extends Expr { * Matches named character properties. For example: * - `\p{Space}` * - `\P{Digit}` upper-case P means inverted - * - `\p{^Word}` caret also means inverted + * - `\p{^Word}` caret also means inverted (not supported in Swift `Regex` but it may be in + * other regex parsers or in future versions of Swift). * * These can occur both inside and outside of character classes. */ @@ -343,7 +344,8 @@ abstract class RegExp extends Expr { /** * Holds if the named character property is inverted. Examples for which it holds: * - `\P{Digit}` upper-case P means inverted - * - `\p{^Word}` caret also means inverted + * - `\p{^Word}` caret also means inverted (not supported in Swift `Regex` but it may be in + * other regex parsers or in future versions of Swift). * - `[[:^digit:]]` * * Examples for which it doesn't hold: @@ -381,8 +383,11 @@ abstract class RegExp extends Expr { // wide hex char \uhhhh this.getChar(start + 1) = "u" and end = start + 6 or + // wide hex char \Uhhhhhhhh + this.getChar(start + 1) = "U" and end = start + 10 + or // escape not handled above; update when adding a new case - not this.getChar(start + 1) in ["x", "u"] and + not this.getChar(start + 1) in ["x", "u", "U"] and not exists(this.getChar(start + 1).toInt()) and end = start + 2 ) diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 725157c6970..bd706e9dab5 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -502,7 +502,7 @@ func myRegexpVariantsTests(myUrl: URL) throws { // BAD // attack string: "X" + "a" x lots - _ = try Regex(#"X(\U00000061|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex(#"X(\U00000061|a)*Y"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"X(\U00000061|b)+Y"#).firstMatch(in: tainted) From 355793f6ca99d1964b97c444fcfd13f085eb86cc Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 15 Jun 2023 18:23:48 +0100 Subject: [PATCH 140/364] Swift: Add support for \u{hhhhhh} escaped characters in regular expressions. --- swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll | 8 ++++++++ swift/ql/test/library-tests/regex/redos_variants.swift | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll index dfe33630401..d1dff2c3ed7 100644 --- a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll +++ b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll @@ -386,6 +386,14 @@ abstract class RegExp extends Expr { // wide hex char \Uhhhhhhhh this.getChar(start + 1) = "U" and end = start + 10 or + // variable width hex char \x{hh...} or \u{hh...} (1-6 digits) + this.getChar(start + 1) = ["x", "u"] and + this.getChar(start + 2) = "{" and + this.getChar(end - 1) = "}" and + end > start and + end <= start + 10 and + not exists(int i | start + 2 < i and i < end - 1 | this.getChar(i) = "}") + or // escape not handled above; update when adding a new case not this.getChar(start + 1) in ["x", "u", "U"] and not exists(this.getChar(start + 1).toInt()) and diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index bd706e9dab5..f11131d1b5b 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -516,10 +516,10 @@ func myRegexpVariantsTests(myUrl: URL) throws { // BAD TODO: we should get this one // attack string: "X" + "a" x lots - _ = try Regex(#"X(\x{061}|a)*Y"#).firstMatch(in: tainted) // $ hasParseFailure= MISSING: redos-vulnerable= + _ = try Regex(#"X(\x{061}|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= // GOOD - _ = try Regex(#"X(\x{061}|b)+Y"#).firstMatch(in: tainted) // $ hasParseFailure + _ = try Regex(#"X(\x{061}|b)+Y"#).firstMatch(in: tainted) // BAD // attack string: "X" + "7" x lots From 39302c62bd3f20d2d02f936cd3940614ff18190a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 15 Jun 2023 20:25:42 +0100 Subject: [PATCH 141/364] Swift: Add support for isDigit and similar. --- swift/ql/lib/codeql/swift/regex/RegexTreeView.qll | 6 +++--- swift/ql/test/library-tests/regex/redos_variants.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll index 3a9738bffec..bc0c3f9fe19 100644 --- a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll +++ b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll @@ -1187,13 +1187,13 @@ private module Impl implements RegexTreeViewSig { or // TODO: expand to cover more properties exists(RegExpNamedCharacterProperty escape | term = escape | - escape.getName().toLowerCase() = "digit" and + escape.getName().toLowerCase() = ["digit", "isdigit"] and if escape.isInverted() then clazz = "D" else clazz = "d" or - escape.getName().toLowerCase() = "space" and + escape.getName().toLowerCase() = ["space", "isspace"] and if escape.isInverted() then clazz = "S" else clazz = "s" or - escape.getName().toLowerCase() = "word" and + escape.getName().toLowerCase() = ["word", "isword"] and if escape.isInverted() then clazz = "W" else clazz = "w" ) } diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index f11131d1b5b..0159e25338e 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -535,9 +535,9 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex(#"X(\P{Digit}|7)+Y"#).firstMatch(in: tainted) - // BAD TODO: we should get this one + // BAD // attack string: "X" + "7" x lots - _ = try Regex(#"X(\p{IsDigit}|7)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex(#"X(\p{IsDigit}|7)*Y"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"X(\p{IsDigit}|b)+Y"#).firstMatch(in: tainted) From df38a12b84abd40b261abf1f852e7b36d5890cbd Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 15 Jun 2023 20:45:11 +0100 Subject: [PATCH 142/364] Swift: Complete the escape sequences fix. --- swift/ql/lib/codeql/swift/regex/RegexTreeView.qll | 13 ++++++++++--- .../test/library-tests/regex/redos_variants.swift | 8 ++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll index bc0c3f9fe19..3484462c989 100644 --- a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll +++ b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll @@ -610,15 +610,22 @@ private module Impl implements RegexTreeViewSig { /** * Holds if this is a unicode escape. */ - private predicate isUnicode() { this.getText().prefix(2) = ["\\u", "\\U"] } + private predicate isUnicode() { this.getText().prefix(2) = ["\\u", "\\U", "\\x"] } /** * Gets the unicode char for this escape. * E.g. for `\u0061` this returns "a". */ - private string getUnicode() { + private string getUnicode() { result = parseHexInt(this.getHexString()).toUnicode() } + + /** + * Gets the part of this escape that is a hexidecimal string. + */ + private string getHexString() { this.isUnicode() and - result = parseHexInt(this.getText().suffix(2)).toUnicode() + if this.getText().matches(["\\x{%", "\\u{%"]) // \x{hh...} or \u{hh...} + then result = this.getText().substring(3, this.getText().length() - 1) + else result = this.getText().suffix(2) // \xhh or \uhhhh or \Uhhhhhhhh } } diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 0159e25338e..1788c828bc6 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -507,16 +507,16 @@ func myRegexpVariantsTests(myUrl: URL) throws { // GOOD _ = try Regex(#"X(\U00000061|b)+Y"#).firstMatch(in: tainted) - // BAD TODO: we should get this one + // BAD // attack string: "X" + "a" x lots - _ = try Regex(#"X(\x61|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex(#"X(\x61|a)*Y"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"X(\x61|b)+Y"#).firstMatch(in: tainted) - // BAD TODO: we should get this one + // BAD // attack string: "X" + "a" x lots - _ = try Regex(#"X(\x{061}|a)*Y"#).firstMatch(in: tainted) // $ MISSING: redos-vulnerable= + _ = try Regex(#"X(\x{061}|a)*Y"#).firstMatch(in: tainted) // $ redos-vulnerable= // GOOD _ = try Regex(#"X(\x{061}|b)+Y"#).firstMatch(in: tainted) From 3e96fe60c5250b92d03a45ba4519c92aa371725b Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Fri, 16 Jun 2023 08:50:47 +0200 Subject: [PATCH 143/364] Go/Java/JS/Python/Ruby: Update the description and qhelp of the ZipSlip query All filesystem operations, not just writes, with paths built from untrusted archive entry names are dangerous --- csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp | 10 +++++----- csharp/ql/src/Security Features/CWE-022/ZipSlip.ql | 8 ++++---- go/ql/src/Security/CWE-022/ZipSlip.qhelp | 10 +++++----- go/ql/src/Security/CWE-022/ZipSlip.ql | 8 ++++---- java/ql/src/Security/CWE/CWE-022/ZipSlip.qhelp | 11 +++++------ java/ql/src/Security/CWE/CWE-022/ZipSlip.ql | 8 ++++---- javascript/ql/src/Security/CWE-022/ZipSlip.qhelp | 10 +++++----- javascript/ql/src/Security/CWE-022/ZipSlip.ql | 8 ++++---- .../src/experimental/Security/CWE-022/ZipSlip.qhelp | 10 +++++----- .../ql/src/experimental/Security/CWE-022/ZipSlip.ql | 8 ++++---- .../ql/src/experimental/cwe-022-zipslip/ZipSlip.qhelp | 10 +++++----- ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.ql | 8 ++++---- 12 files changed, 54 insertions(+), 55 deletions(-) diff --git a/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp b/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp index bee5d819836..e1e2974ed4f 100644 --- a/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp +++ b/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp @@ -3,16 +3,16 @@ "qhelp.dtd"> -

    Extracting files from a malicious zip archive without validating that the destination file path -is within the destination directory can cause files outside the destination directory to be -overwritten, due to the possible presence of directory traversal elements (..) in +

    Accessing filesystem paths built from the name of an archive entry without validating that the +destination file path is within the destination directory can allow an attacker to access +unexpected resources, due to the possible presence of directory traversal elements (..) in archive paths.

    Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (..). If these -file paths are used to determine an output file to write the contents of the archive item to, then -the file may be written to an unexpected location. This can result in sensitive information being +file paths are used to create a filesystem path, then a file operation may happen in an +unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files.

    diff --git a/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql b/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql index 87850cde7d6..25a1e9bcd19 100644 --- a/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql +++ b/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql @@ -1,8 +1,8 @@ /** - * @name Arbitrary file write during zip extraction ("Zip Slip") - * @description Extracting files from a malicious zip archive without validating that the - * destination file path is within the destination directory can cause files outside - * the destination directory to be overwritten. + * @name Arbitrary file access during archive extraction ("Zip Slip") + * @description Accessing filesystem paths built from the name of an archive entry without + * validating that the destination file path is within the destination directory + * can allow an attacker to access unexpected resources. * @kind path-problem * @id cs/zipslip * @problem.severity error diff --git a/go/ql/src/Security/CWE-022/ZipSlip.qhelp b/go/ql/src/Security/CWE-022/ZipSlip.qhelp index 1322dc18c13..1c47eac9a53 100644 --- a/go/ql/src/Security/CWE-022/ZipSlip.qhelp +++ b/go/ql/src/Security/CWE-022/ZipSlip.qhelp @@ -5,9 +5,9 @@

    -Extracting files from a malicious zip archive without validating that the destination file path -is within the destination directory can cause files outside the destination directory to be -overwritten, due to the possible presence of directory traversal elements (..) in +Accessing filesystem paths built from the name of an archive entry without validating that the +destination file path is within the destination directory can allow an attacker to access +unexpected resources, due to the possible presence of directory traversal elements (..) in archive paths.

    @@ -15,8 +15,8 @@ archive paths. Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (..). If these -file paths are used to determine which output file the contents of an archive item should be written to, then -the file may be written to an unexpected location. This can result in sensitive information being +file paths are used to create a filesystem path, then a file operation may happen in an +unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files.

    diff --git a/go/ql/src/Security/CWE-022/ZipSlip.ql b/go/ql/src/Security/CWE-022/ZipSlip.ql index ceec7dc57e3..27c18248ad5 100644 --- a/go/ql/src/Security/CWE-022/ZipSlip.ql +++ b/go/ql/src/Security/CWE-022/ZipSlip.ql @@ -1,8 +1,8 @@ /** - * @name Arbitrary file write during zip extraction ("zip slip") - * @description Extracting files from a malicious zip archive without validating that the - * destination file path is within the destination directory can cause files outside - * the destination directory to be overwritten. + * @name Arbitrary file access during archive extraction ("Zip Slip") + * @description Accessing filesystem paths built from the name of an archive entry without + * validating that the destination file path is within the destination directory + * can allow an attacker to access unexpected resources. * @kind path-problem * @id go/zipslip * @problem.severity error diff --git a/java/ql/src/Security/CWE/CWE-022/ZipSlip.qhelp b/java/ql/src/Security/CWE/CWE-022/ZipSlip.qhelp index adea1b89c49..726b2d15cb6 100644 --- a/java/ql/src/Security/CWE/CWE-022/ZipSlip.qhelp +++ b/java/ql/src/Security/CWE/CWE-022/ZipSlip.qhelp @@ -3,17 +3,16 @@ "qhelp.dtd"> -

    Extracting files from a malicious zip archive (or another archive format) -without validating that the destination file path -is within the destination directory can cause files outside the destination directory to be -overwritten, due to the possible presence of directory traversal elements (..) in +

    Accessing filesystem paths built from the name of an archive entry without validating that the +destination file path is within the destination directory can allow an attacker to access +unexpected resources, due to the possible presence of directory traversal elements (..) in archive paths.

    Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (..). If these -file paths are used to determine an output file to write the contents of the archive item to, then -the file may be written to an unexpected location. This can result in sensitive information being +file paths are used to create a filesystem path, then a file operation may happen in an +unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files.

    diff --git a/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql b/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql index 3488c97c057..2c48ecb2aa1 100644 --- a/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql +++ b/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql @@ -1,8 +1,8 @@ /** - * @name Arbitrary file write during archive extraction ("Zip Slip") - * @description Extracting files from a malicious archive without validating that the - * destination file path is within the destination directory can cause files outside - * the destination directory to be overwritten. + * @name Arbitrary file access during archive extraction ("Zip Slip") + * @description Accessing filesystem paths built from the name of an archive entry without + * validating that the destination file path is within the destination directory + * can allow an attacker to access unexpected resources. * @kind path-problem * @id java/zipslip * @problem.severity error diff --git a/javascript/ql/src/Security/CWE-022/ZipSlip.qhelp b/javascript/ql/src/Security/CWE-022/ZipSlip.qhelp index d9dc0fb67a8..bbb3824e41e 100644 --- a/javascript/ql/src/Security/CWE-022/ZipSlip.qhelp +++ b/javascript/ql/src/Security/CWE-022/ZipSlip.qhelp @@ -4,16 +4,16 @@ -

    Extracting files from a malicious zip archive without validating that the destination file path -is within the destination directory can cause files outside the destination directory to be -overwritten, due to the possible presence of directory traversal elements (..) in +

    Accessing filesystem paths built from the name of an archive entry without validating that the +destination file path is within the destination directory can allow an attacker to access +unexpected resources, due to the possible presence of directory traversal elements (..) in archive paths.

    Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (..). If these -file paths are used to determine an output file to write the contents of the archive item to, then -the file may be written to an unexpected location. This can result in sensitive information being +file paths are used to create a filesystem path, then a file operation may happen in an +unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files.

    diff --git a/javascript/ql/src/Security/CWE-022/ZipSlip.ql b/javascript/ql/src/Security/CWE-022/ZipSlip.ql index 0380031ad66..f9c468c388a 100644 --- a/javascript/ql/src/Security/CWE-022/ZipSlip.ql +++ b/javascript/ql/src/Security/CWE-022/ZipSlip.ql @@ -1,8 +1,8 @@ /** - * @name Arbitrary file write during zip extraction ("Zip Slip") - * @description Extracting files from a malicious zip archive without validating that the - * destination file path is within the destination directory can cause files outside - * the destination directory to be overwritten. + * @name Arbitrary file access during archive extraction ("Zip Slip") + * @description Accessing filesystem paths built from the name of an archive entry without + * validating that the destination file path is within the destination directory + * can allow an attacker to access unexpected resources. * @kind path-problem * @id js/zipslip * @problem.severity error diff --git a/python/ql/src/experimental/Security/CWE-022/ZipSlip.qhelp b/python/ql/src/experimental/Security/CWE-022/ZipSlip.qhelp index 89260db7bd7..dfd563ea19b 100644 --- a/python/ql/src/experimental/Security/CWE-022/ZipSlip.qhelp +++ b/python/ql/src/experimental/Security/CWE-022/ZipSlip.qhelp @@ -4,16 +4,16 @@ -

    Extracting files from a malicious zip archive without validating that the destination file path -is within the destination directory can cause files outside the destination directory to be -overwritten, due to the possible presence of directory traversal elements (..) in +

    Accessing filesystem paths built from the name of an archive entry without validating that the +destination file path is within the destination directory can allow an attacker to access +unexpected resources, due to the possible presence of directory traversal elements (..) in archive paths.

    Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (..). If these -file paths are used to determine an output file to write the contents of the archive item to, then -the file may be written to an unexpected location. This can result in sensitive information being +file paths are used to create a filesystem path, then a file operation may happen in an +unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files.

    diff --git a/python/ql/src/experimental/Security/CWE-022/ZipSlip.ql b/python/ql/src/experimental/Security/CWE-022/ZipSlip.ql index aea193dde36..b00214cfe68 100644 --- a/python/ql/src/experimental/Security/CWE-022/ZipSlip.ql +++ b/python/ql/src/experimental/Security/CWE-022/ZipSlip.ql @@ -1,8 +1,8 @@ /** - * @name Arbitrary file write during archive extraction ("Zip Slip") - * @description Extracting files from a malicious archive without validating that the - * destination file path is within the destination directory can cause files outside - * the destination directory to be overwritten. + * @name Arbitrary file access during archive extraction ("Zip Slip") + * @description Accessing filesystem paths built from the name of an archive entry without + * validating that the destination file path is within the destination directory + * can allow an attacker to access unexpected resources. * @kind path-problem * @id py/zipslip * @problem.severity error diff --git a/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.qhelp b/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.qhelp index 759be8d95d0..2794db7efbd 100644 --- a/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.qhelp +++ b/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.qhelp @@ -4,16 +4,16 @@ -

    Extracting files from a malicious tar archive without validating that the destination file path -is within the destination directory can cause files outside the destination directory to be -overwritten, due to the possible presence of directory traversal elements (..) in +

    Accessing filesystem paths built from the name of an archive entry without validating that the +destination file path is within the destination directory can allow an attacker to access +unexpected resources, due to the possible presence of directory traversal elements (..) in archive paths.

    Tar archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain unexpected special elements such as the directory traversal element (..). If these -file paths are used to determine an output file to write the contents of the archive item to, then -the file may be written to an unexpected location. This can result in sensitive information being +file paths are used to create a filesystem path, then a file operation may happen in an +unexpected location. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files.

    diff --git a/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.ql b/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.ql index e8be92fff75..709e89f98e8 100644 --- a/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.ql +++ b/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.ql @@ -1,8 +1,8 @@ /** - * @name Arbitrary file write during zipfile/tarfile extraction - * @description Extracting files from a malicious tar archive without validating that the - * destination file path is within the destination directory can cause files outside - * the destination directory to be overwritten. + * @name Arbitrary file access during archive extraction ("Zip Slip") + * @description Accessing filesystem paths built from the name of an archive entry without + * validating that the destination file path is within the destination directory + * can allow an attacker to access unexpected resources. * @kind path-problem * @id rb/zip-slip * @problem.severity error From c97868f7743a5c223933b1ff9c1662586c2fe441 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Fri, 16 Jun 2023 09:01:02 +0200 Subject: [PATCH 144/364] Add change notes --- csharp/ql/src/change-notes/2023-06-16-zipslip-rename.md | 4 ++++ go/ql/src/change-notes/2023-06-16-zipslip-rename.md | 4 ++++ java/ql/src/change-notes/2023-06-16-zipslip-rename.md | 4 ++++ javascript/ql/src/change-notes/2023-06-16-zipslip-rename.md | 4 ++++ python/ql/src/change-notes/2023-06-16-zipslip-rename.md | 4 ++++ ruby/ql/src/change-notes/2023-06-16-zipslip-rename.md | 4 ++++ 6 files changed, 24 insertions(+) create mode 100644 csharp/ql/src/change-notes/2023-06-16-zipslip-rename.md create mode 100644 go/ql/src/change-notes/2023-06-16-zipslip-rename.md create mode 100644 java/ql/src/change-notes/2023-06-16-zipslip-rename.md create mode 100644 javascript/ql/src/change-notes/2023-06-16-zipslip-rename.md create mode 100644 python/ql/src/change-notes/2023-06-16-zipslip-rename.md create mode 100644 ruby/ql/src/change-notes/2023-06-16-zipslip-rename.md diff --git a/csharp/ql/src/change-notes/2023-06-16-zipslip-rename.md b/csharp/ql/src/change-notes/2023-06-16-zipslip-rename.md new file mode 100644 index 00000000000..2816d74945c --- /dev/null +++ b/csharp/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The query "Arbitrary file write during zip extraction ("Zip Slip")" (`cs/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". diff --git a/go/ql/src/change-notes/2023-06-16-zipslip-rename.md b/go/ql/src/change-notes/2023-06-16-zipslip-rename.md new file mode 100644 index 00000000000..9e9d1483ad6 --- /dev/null +++ b/go/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The query "Arbitrary file write during zip extraction ("zip slip")" (`go/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". diff --git a/java/ql/src/change-notes/2023-06-16-zipslip-rename.md b/java/ql/src/change-notes/2023-06-16-zipslip-rename.md new file mode 100644 index 00000000000..39316e46f5d --- /dev/null +++ b/java/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The query "Arbitrary file write during archive extraction ("Zip Slip")" (`java/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". diff --git a/javascript/ql/src/change-notes/2023-06-16-zipslip-rename.md b/javascript/ql/src/change-notes/2023-06-16-zipslip-rename.md new file mode 100644 index 00000000000..0d866964347 --- /dev/null +++ b/javascript/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The query "Arbitrary file write during zip extraction ("Zip Slip")" (`js/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". diff --git a/python/ql/src/change-notes/2023-06-16-zipslip-rename.md b/python/ql/src/change-notes/2023-06-16-zipslip-rename.md new file mode 100644 index 00000000000..50313eb7d27 --- /dev/null +++ b/python/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The query "Arbitrary file write during archive extraction ("Zip Slip")" (`py/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". diff --git a/ruby/ql/src/change-notes/2023-06-16-zipslip-rename.md b/ruby/ql/src/change-notes/2023-06-16-zipslip-rename.md new file mode 100644 index 00000000000..8e56e960ec4 --- /dev/null +++ b/ruby/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The experimental query "Arbitrary file write during zipfile/tarfile extraction" (`ruby/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". From daf274314331318ecffd16e1bf7de399fe06cadc Mon Sep 17 00:00:00 2001 From: Jean Helie Date: Wed, 14 Jun 2023 15:07:12 +0200 Subject: [PATCH 145/364] only use neutral models of kind "sink" --- .../src/Telemetry/AutomodelApplicationModeCharacteristics.qll | 2 +- java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/Telemetry/AutomodelApplicationModeCharacteristics.qll b/java/ql/src/Telemetry/AutomodelApplicationModeCharacteristics.qll index 86aff731ba2..9b2eecb0307 100644 --- a/java/ql/src/Telemetry/AutomodelApplicationModeCharacteristics.qll +++ b/java/ql/src/Telemetry/AutomodelApplicationModeCharacteristics.qll @@ -79,7 +79,7 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig predicate isNeutral(Endpoint e) { exists(string package, string type, string name, string signature | sinkSpec(e, package, type, name, signature, _, _) and - ExternalFlow::neutralModel(package, type, name, [signature, ""], _, _) + ExternalFlow::neutralModel(package, type, name, [signature, ""], "sink", _) ) } diff --git a/java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll b/java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll index da37726d8f0..5dbca626159 100644 --- a/java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll +++ b/java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll @@ -60,7 +60,7 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig { predicate isNeutral(Endpoint e) { exists(string package, string type, string name, string signature | sinkSpec(e, package, type, name, signature, _, _) and - ExternalFlow::neutralModel(package, type, name, [signature, ""], _, _) + ExternalFlow::neutralModel(package, type, name, [signature, ""], "sink", _) ) } From baf6b7494534bef30e58ee928029c52e1a6f3851 Mon Sep 17 00:00:00 2001 From: Jean Helie Date: Wed, 14 Jun 2023 17:54:16 +0200 Subject: [PATCH 146/364] use new sink mad kinds and simplify isKnownKind predicate --- ...utomodelApplicationModeCharacteristics.qll | 4 +-- .../src/Telemetry/AutomodelEndpointTypes.qll | 10 +++---- .../AutomodelFrameworkModeCharacteristics.qll | 2 +- java/ql/src/Telemetry/AutomodelJavaUtil.qll | 26 +++++-------------- .../AutomodelSharedCharacteristics.qll | 8 ++++-- 5 files changed, 20 insertions(+), 30 deletions(-) diff --git a/java/ql/src/Telemetry/AutomodelApplicationModeCharacteristics.qll b/java/ql/src/Telemetry/AutomodelApplicationModeCharacteristics.qll index 9b2eecb0307..51e786eebdc 100644 --- a/java/ql/src/Telemetry/AutomodelApplicationModeCharacteristics.qll +++ b/java/ql/src/Telemetry/AutomodelApplicationModeCharacteristics.qll @@ -59,13 +59,13 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig e.getType() instanceof NumberType ) or - t instanceof AutomodelEndpointTypes::TaintedPathSinkType and + t instanceof AutomodelEndpointTypes::PathInjectionSinkType and e instanceof PathSanitizer::PathInjectionSanitizer } RelatedLocation asLocation(Endpoint e) { result = e.asExpr() } - predicate isKnownKind = AutomodelJavaUtil::isKnownKind/3; + predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2; predicate isSink(Endpoint e, string kind) { exists(string package, string type, string name, string signature, string ext, string input | diff --git a/java/ql/src/Telemetry/AutomodelEndpointTypes.qll b/java/ql/src/Telemetry/AutomodelEndpointTypes.qll index 7414837b605..618fa4bc7dd 100644 --- a/java/ql/src/Telemetry/AutomodelEndpointTypes.qll +++ b/java/ql/src/Telemetry/AutomodelEndpointTypes.qll @@ -40,18 +40,18 @@ class NegativeSinkType extends SinkType { } /** A sink relevant to the SQL injection query */ -class SqlSinkType extends SinkType { - SqlSinkType() { this = "sql" } +class SqlInjectionSinkType extends SinkType { + SqlInjectionSinkType() { this = "sql-injection" } } /** A sink relevant to the tainted path injection query. */ -class TaintedPathSinkType extends SinkType { - TaintedPathSinkType() { this = "tainted-path" } +class PathInjectionSinkType extends SinkType { + PathInjectionSinkType() { this = "path-injection" } } /** A sink relevant to the SSRF query. */ class RequestForgerySinkType extends SinkType { - RequestForgerySinkType() { this = "ssrf" } + RequestForgerySinkType() { this = "request-forgery" } } /** A sink relevant to the command injection query. */ diff --git a/java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll b/java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll index 5dbca626159..bc5c3b59a91 100644 --- a/java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll +++ b/java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll @@ -48,7 +48,7 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig { RelatedLocation asLocation(Endpoint e) { result = e.asParameter() } - predicate isKnownKind = AutomodelJavaUtil::isKnownKind/3; + predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2; predicate isSink(Endpoint e, string kind) { exists(string package, string type, string name, string signature, string ext, string input | diff --git a/java/ql/src/Telemetry/AutomodelJavaUtil.qll b/java/ql/src/Telemetry/AutomodelJavaUtil.qll index 215ab1fca1a..03b73da1015 100644 --- a/java/ql/src/Telemetry/AutomodelJavaUtil.qll +++ b/java/ql/src/Telemetry/AutomodelJavaUtil.qll @@ -27,31 +27,17 @@ class DollarAtString extends string { * Holds for all combinations of MaD kinds (`kind`) and their human readable * descriptions. */ -predicate isKnownKind( - string kind, string humanReadableKind, AutomodelEndpointTypes::EndpointType type -) { - kind = "read-file" and - humanReadableKind = "read file" and - type instanceof AutomodelEndpointTypes::TaintedPathSinkType +predicate isKnownKind(string kind, AutomodelEndpointTypes::EndpointType type) { + kind = "path-injection" and + type instanceof AutomodelEndpointTypes::PathInjectionSinkType or - kind = "create-file" and - humanReadableKind = "create file" and - type instanceof AutomodelEndpointTypes::TaintedPathSinkType + kind = "sql-injection" and + type instanceof AutomodelEndpointTypes::SqlInjectionSinkType or - kind = "sql" and - humanReadableKind = "mad modeled sql" and - type instanceof AutomodelEndpointTypes::SqlSinkType - or - kind = "open-url" and - humanReadableKind = "open url" and - type instanceof AutomodelEndpointTypes::RequestForgerySinkType - or - kind = "jdbc-url" and - humanReadableKind = "jdbc url" and + kind = "request-forgery" and type instanceof AutomodelEndpointTypes::RequestForgerySinkType or kind = "command-injection" and - humanReadableKind = "command injection" and type instanceof AutomodelEndpointTypes::CommandInjectionSinkType } diff --git a/java/ql/src/Telemetry/AutomodelSharedCharacteristics.qll b/java/ql/src/Telemetry/AutomodelSharedCharacteristics.qll index f23340bf34f..b077f77deb9 100644 --- a/java/ql/src/Telemetry/AutomodelSharedCharacteristics.qll +++ b/java/ql/src/Telemetry/AutomodelSharedCharacteristics.qll @@ -50,7 +50,7 @@ signature module CandidateSig { /** * Defines what MaD kinds are known, and what endpoint type they correspond to. */ - predicate isKnownKind(string kind, string humanReadableLabel, EndpointType type); + predicate isKnownKind(string kind, EndpointType type); /** * Holds if `e` is a flow sanitizer, and has type `t`. @@ -276,7 +276,11 @@ module SharedCharacteristics { string madKind; Candidate::EndpointType endpointType; - KnownSinkCharacteristic() { Candidate::isKnownKind(madKind, this, endpointType) } + KnownSinkCharacteristic() { + Candidate::isKnownKind(madKind, endpointType) and + // bind "this" to a unique string differing from that of the SinkType classes + this = madKind + "-characteristic" + } override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isSink(e, madKind) } From afafaac0d785c0f7b31345aa4a28e25f99c58d80 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 16 Jun 2023 14:41:36 +0200 Subject: [PATCH 147/364] Python: Fix typo --- .../semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index 8817cdf21ce..bac194aae9e 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -243,7 +243,7 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { Node returnOf(Node callable, SummaryComponent return) { return = FlowSummary::SummaryComponent::return() and - // `result` should be the return value of a callable expresion (lambda or function) referenced by `callable` + // `result` should be the return value of a callable expression (lambda or function) referenced by `callable` result.asCfgNode() = callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getAReturnValueFlowNode() } From fb6955edf98bb51054650b3e9187d7451d9ab901 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 16 Jun 2023 14:43:45 +0200 Subject: [PATCH 148/364] Python: Add tests of methods in summaries --- .../dataflow/summaries/summaries.py | 18 ++++++++++++++++++ .../typetracking-summaries/summaries.py | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/python/ql/test/experimental/dataflow/summaries/summaries.py b/python/ql/test/experimental/dataflow/summaries/summaries.py index 1532a5393d8..806b39f6dc8 100644 --- a/python/ql/test/experimental/dataflow/summaries/summaries.py +++ b/python/ql/test/experimental/dataflow/summaries/summaries.py @@ -66,3 +66,21 @@ SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" from json import loads as json_loads tainted_resultlist = json_loads(SOURCE) SINK(tainted_resultlist[0]) # $ flow="SOURCE, l:-1 -> tainted_resultlist[0]" + + +# Class methods are not handled right now + +class MyClass: + @staticmethod + def foo(x): + return x + + def bar(self, x): + return x + +through_staticmethod = apply_lambda(MyClass.foo, SOURCE) +through_staticmethod # $ MISSING: flow + +mc = MyClass() +through_method = apply_lambda(mc.bar, SOURCE) +through_method # $ MISSING: flow diff --git a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py index 5801b8e7961..f838032b063 100644 --- a/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py +++ b/python/ql/test/experimental/dataflow/typetracking-summaries/summaries.py @@ -59,3 +59,20 @@ r # $ tracked y # $ tracked=secret TTS_set_secret(y, tracked) # $ tracked tracked=secret y.secret # $ tracked tracked=secret + +# Class methods are not handled right now + +class MyClass: + @staticmethod + def foo(x): + return x + + def bar(self, x): + return x + +through_staticmethod = TTS_apply_lambda(MyClass.foo, tracked) # $ tracked +through_staticmethod # $ MISSING: tracked + +mc = MyClass() +through_method = TTS_apply_lambda(mc.bar, tracked) # $ tracked +through_method # $ MISSING: tracked From aedd9f5f6b1ea5f2e2ab2045c4ab331d90688261 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Fri, 26 May 2023 15:00:03 +0100 Subject: [PATCH 149/364] add QL specification section on module instantiations --- .../ql-language-specification.rst | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst index 71dcbdce571..59510bc8edd 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -199,10 +199,21 @@ Kinds of modules A module may be: +- A *declared module*, if it is defined by the ``module`` or ``ql`` grammar rules. +- A *non-declared module*, if it is not a *declared module*. + +A *declared module* may be: + - A *file module*, if it is defined implicitly by a QL file or a QLL file. - A *query module*, if it is defined implicitly by a QL file. - A *library module*, if it is not a query module. +A *non-declared module* may be: + +- A *built-in module*. +- An *instantiated module* (see :ref:`Parameterized modules`). +- An *instantiation-nested module* (see :ref:`Parameterized modules`). + A query module must contain one or more queries. Import directives @@ -249,6 +260,67 @@ For qualified identifiers (``a.b``): A qualified module identifier is only valid within an import. +.. _Parameterized modules: + +Parameterized modules +~~~~~~~~~~~~~~~~~~~~~ + +Modules with parameters are called *parameterized modules*. A *declared module* has parameters if and only if it is a *library module* and its declaration uses the ``parameters`` syntax. + +*Parameterized modules* can be instantiated with arguments that match the signatures of the parameters: + +- Given a type signature, the corresponding argument must be a type that transitively extends the specified ``extends`` types and is a transitive subtype of the specified ``instanceof`` types. +- Given a predicate signature, the corresponding argument must be a predicate with exactly matching relational types. +- Given a module signature, the corresponding argument must be a module that exports all the specified type and predicate members. Furthermore, the module must be declared as matching the module signature via the ``implements`` syntax. + +The result of instantiating a *parameterized module* is an *instantiated module*. The parameterized module is called the *underlying module* of the *instantiated module*. + +Instantiation-relative and instantiation-nested entities +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Given an *instantiated module*, every entity has a corresponding entity called the *instantiation-relative* entity, which is determined as follows: + +- If the entity is the *underlying module*, its *instantiation-relative entity* is the *instantiated module*. +- If the entity is a parameter of the *underlying module*, its *instantiation-relative entity* is the corresponding argument. +- If the entity is declared inside the *underlying module* or its nested modules, its *instantiation-relative* entity is an *instantiation-nested* entity that is generated by the module instantiation. Parameters of any modules that are nested inside the *underlying module* are considered declared inside the module for this purpose. +- Otherwise, the entity's *instantiation-relative* entity is the initial entity itself. + +When the *instantiation-relative* entity of an entity is an *instantiation-nested* entity, then the initial entity is called the *underlying nested* entity of the *instantiation-nested* entity*, the *instantiated module* is called the *instantiation root* of the *instantiation-nested* entity, and the *underlying module* is called the *underlying root* of the *instantiation-nested* entity. + +The components of an *instantiation-nested* entity are the *instantiation-relative* entities of the components of its *underlying nested* entity. Among other things, this applies to: + +- values in the exported environments of *instantiation-nested* modules, +- relational types of *instantiation-nested* predicates and predicate signatures, +- required signatures of *instantiation-nested* parameters, +- parameters of an *instantiation-nested* *parameterized module*, +- fields and member predicates of *instantiation-nested* dataclasses. + +Given an *instantiated module*, any alias in the program has a corresponding alias called the *instantiation-relative* alias, which targets the *instantiation-relative* entity. + +Applicative instantiation +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Every entity has an *underlying completely uninstantiated* entity that is determined as follows: + +- If the entity is an *instantiated module*, its *underlying completely uninstantiated* entity is the *underlying completely uninstantiated* entity of the *underlying module*. +- If the entity is an *instantiation-nested* entity, its *underlying completely uninstantiated* entity is the *underlying completely uninstantiated* entity of the *underlying nested* entity. +- Otherwise, its *underlying completely uninstantiated* entity is the entity itself. + +An entity is called *completely uninstantiated* entity if it is its own *underlying completely uninstantiated* entity. + +Every *completely uninstantiated* entity has a *relevant set of parameters*, which is the set of all parameters of all the modules that the entity is transitively nested inside. For entities that are not nested inside any modules, the *relevant set of parameters* is empty. + +Note that the *relevant set of parameters* by construction contains only *completely uninstantiated* parameters. + +For a *completely uninstantiated* parameter, the *bottom-up instantiation-resolved* parameter relative to an entity is defined as: + +- If the entity is an *instantiated module* or an *instantiation-nested* entity, the *bottom-up instantiation-resolved* parameter is the *instantiation-relative* parameter of the *bottom-up instantiation-resolved* parameter relative to the *underlying module*. +- Otherwise, the *bottom-up instantiation-resolved* parameter is the parameter itself. + +Two *instantiated modules* or two *instantiation-nested* entities are considered *equivalent* if they have the same *underlying completely uninstantiated* entity and each parameter in its *relevant set of parameters* has the same *bottom-up instantiation-resolved* parameter relative to either *instantiated module*. + +Module instantiation is applicative, meaning that *equivalent* *instantiated modules* and *equivalent* *instantiation-nested* entities are indistinguishable. + Module references and active modules ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 45426b928929ec68208b5b3506a33387927aa894 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Tue, 13 Jun 2023 15:55:47 +0100 Subject: [PATCH 150/364] mention parameters and instantiation-nested types --- docs/codeql/ql-language-reference/ql-language-specification.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst index 59510bc8edd..f6edaf2e121 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -340,7 +340,7 @@ QL is a typed language. This section specifies the kinds of types available, the Kinds of types ~~~~~~~~~~~~~~ -Types in QL are either *primitive* types, *database* types, *class* types, *character* types or *class domain* types. +Types in QL are either *primitive* types, *database* types, *class* types, *character* types, *class domain* types, type *parameters*, or *instantiation-nested* types. The primitive types are ``boolean``, ``date``, ``float``, ``int``, and ``string``. From 1ed3baea1739fb527d36a6233e5bc960d8e5b75b Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Fri, 16 Jun 2023 16:03:25 +0100 Subject: [PATCH 151/364] mention instantiation in the section on module resolution --- .../ql-language-specification.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst index f6edaf2e121..a1b5eb0068d 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -219,15 +219,17 @@ A query module must contain one or more queries. Import directives ~~~~~~~~~~~~~~~~~ -An import directive refers to a module identifier: +An import directive refers to a module expression: :: import ::= annotations "import" importModuleExpr ("as" modulename)? - qualId ::= simpleId | qualId "." simpleId + importModuleExpr ::= importModuleId arguments? - importModuleExpr ::= qualId | importModuleExpr "::" modulename arguments? + importModuleId ::= qualId | importModuleExpr "::" modulename + + qualId ::= simpleId | qualId "." simpleId arguments ::= "<" argument ("," argument)* ">" @@ -260,6 +262,10 @@ For qualified identifiers (``a.b``): A qualified module identifier is only valid within an import. +Module expressions contain a module identifier and optional arguments. If arguments are present, the module expression instantiates the module that the identifier resolves to (see :ref:`Parameterized modules`). + +Module expressions cannot refer to :ref:`Parameterized modules`. Instead, parameterized modules must always be fully instantiated when they are referenced. + .. _Parameterized modules: Parameterized modules @@ -361,7 +367,9 @@ With the exception of class domain types and character types (which cannot be re type ::= (moduleExpr "::")? classname | dbasetype | "boolean" | "date" | "float" | "int" | "string" - moduleExpr ::= modulename arguments? | moduleExpr "::" modulename arguments? + moduleExpr ::= moduleId arguments? + + moduleId ::= modulename | moduleExpr "::" modulename A type reference is resolved to a type as follows: From 096e9a4ba4bfe92f3af1a47a0f1c5f128b71f07e Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Fri, 16 Jun 2023 17:04:47 +0100 Subject: [PATCH 152/364] Kotlin: Avoid another cause of ConcurrentModificationException with 1.9 --- java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index c471662e631..3db4321d094 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -5316,7 +5316,10 @@ open class KotlinFileExtractor( private fun extractTypeAccessRecursive(t: IrType, location: Label, parent: Label, idx: Int, typeContext: TypeContext = TypeContext.OTHER): Label { val typeAccessId = extractTypeAccess(useType(t, typeContext), location, parent, idx) if (t is IrSimpleType) { - t.arguments.forEachIndexed { argIdx, arg -> + // From 1.9, the list might change when we call erase, + // so we make a copy that it is safe to iterate over. + val argumentsCopy = t.arguments.toList() + argumentsCopy.forEachIndexed { argIdx, arg -> extractWildcardTypeAccessRecursive(arg, location, typeAccessId, argIdx) } } From bc48968defe3117d4a4453347da52565a482074d Mon Sep 17 00:00:00 2001 From: Alexandre Boulgakov Date: Fri, 16 Jun 2023 17:22:43 +0100 Subject: [PATCH 153/364] Swift: Build incompatible OS diagnostic on all platforms. --- swift/BUILD.bazel | 6 +++--- swift/logging/SwiftLogging.cpp | 4 ++++ swift/rules.bzl | 12 +++++++----- swift/tools/autobuilder-diagnostics/BUILD.bazel | 2 ++ 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/swift/BUILD.bazel b/swift/BUILD.bazel index b5042dc19d8..af21fcc0c66 100644 --- a/swift/BUILD.bazel +++ b/swift/BUILD.bazel @@ -85,12 +85,12 @@ pkg_filegroup( ":swift-test-sdk-arch", ":resource-dir-arch", ] + select({ - "@platforms//os:linux": [ - ":incompatible-os", - ], "@platforms//os:macos": [ ":xcode-autobuilder", ], + "//conditions:default": [ + ":incompatible-os", + ], }), visibility = ["//visibility:public"], ) diff --git a/swift/logging/SwiftLogging.cpp b/swift/logging/SwiftLogging.cpp index 952021f740f..6c065e858c1 100644 --- a/swift/logging/SwiftLogging.cpp +++ b/swift/logging/SwiftLogging.cpp @@ -3,7 +3,11 @@ #include #include #include +#ifdef _WIN32 +#include +#else #include +#endif #include "absl/strings/str_cat.h" #define LEVEL_REGEX_PATTERN "trace|debug|info|warning|error|critical|no_logs" diff --git a/swift/rules.bzl b/swift/rules.bzl index ba9e4b0e8bf..6ed085de63c 100644 --- a/swift/rules.bzl +++ b/swift/rules.bzl @@ -10,11 +10,13 @@ def _wrap_cc(rule, kwargs): # temporary, before we do universal merging "-universal_binaries", ]) - _add_args(kwargs, "target_compatible_with", select({ - "@platforms//os:linux": [], - "@platforms//os:macos": [], - "//conditions:default": ["@platforms//:incompatible"], - })) + if "target_compatible_with" not in kwargs: + # Restrict to Linux or macOS by default, but allow overriding + _add_args(kwargs, "target_compatible_with", select({ + "@platforms//os:linux": [], + "@platforms//os:macos": [], + "//conditions:default": ["@platforms//:incompatible"], + })) rule(**kwargs) def swift_cc_binary(**kwargs): diff --git a/swift/tools/autobuilder-diagnostics/BUILD.bazel b/swift/tools/autobuilder-diagnostics/BUILD.bazel index 32d6ce703e9..8e76b553c73 100644 --- a/swift/tools/autobuilder-diagnostics/BUILD.bazel +++ b/swift/tools/autobuilder-diagnostics/BUILD.bazel @@ -7,4 +7,6 @@ swift_cc_binary( deps = [ "//swift/logging", ], + # No restrictions (Windows allowed) + target_compatible_with = [], ) From 2bb3101316265c5d8640d520b68daac68269c19f Mon Sep 17 00:00:00 2001 From: Alexandre Boulgakov Date: Fri, 16 Jun 2023 17:22:43 +0100 Subject: [PATCH 154/364] Swift: Rename incompatible OS diagnostic to clarify that it's for the autobuilder. --- swift/BUILD.bazel | 8 ++++---- swift/tools/autobuild.sh | 2 +- .../AutobuilderIncompatibleOs.cpp} | 0 .../{autobuilder-diagnostics => diagnostics}/BUILD.bazel | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) rename swift/tools/{autobuilder-diagnostics/IncompatibleOs.cpp => diagnostics/AutobuilderIncompatibleOs.cpp} (100%) rename swift/tools/{autobuilder-diagnostics => diagnostics}/BUILD.bazel (72%) diff --git a/swift/BUILD.bazel b/swift/BUILD.bazel index af21fcc0c66..8ea073e991a 100644 --- a/swift/BUILD.bazel +++ b/swift/BUILD.bazel @@ -59,8 +59,8 @@ pkg_runfiles( ) pkg_runfiles( - name = "incompatible-os", - srcs = ["//swift/tools/autobuilder-diagnostics:incompatible-os"], + name = "diagnostics", + srcs = ["//swift/tools/diagnostics:autobuilder-incompatible-os"], prefix = "tools/" + codeql_platform, ) @@ -89,7 +89,7 @@ pkg_filegroup( ":xcode-autobuilder", ], "//conditions:default": [ - ":incompatible-os", + ":diagnostics", ], }), visibility = ["//visibility:public"], @@ -122,7 +122,7 @@ generate_cmake( "//swift/extractor:extractor.real", "//swift/logging/tests/assertion-diagnostics:assert-false", ] + select({ - "@platforms//os:linux": ["//swift/tools/autobuilder-diagnostics:incompatible-os"], + "@platforms//os:linux": ["//swift/tools/diagnostics:autobuilder-incompatible-os"], "@platforms//os:macos": ["//swift/xcode-autobuilder"], }), visibility = ["//visibility:public"], diff --git a/swift/tools/autobuild.sh b/swift/tools/autobuild.sh index 9be42363be6..3e25e800ced 100755 --- a/swift/tools/autobuild.sh +++ b/swift/tools/autobuild.sh @@ -3,5 +3,5 @@ if [[ "$OSTYPE" == "darwin"* ]]; then exec "${CODEQL_EXTRACTOR_SWIFT_ROOT}/tools/${CODEQL_PLATFORM}/xcode-autobuilder" else - exec "${CODEQL_EXTRACTOR_SWIFT_ROOT}/tools/${CODEQL_PLATFORM}/incompatible-os" + exec "${CODEQL_EXTRACTOR_SWIFT_ROOT}/tools/${CODEQL_PLATFORM}/autobuilder-incompatible-os" fi diff --git a/swift/tools/autobuilder-diagnostics/IncompatibleOs.cpp b/swift/tools/diagnostics/AutobuilderIncompatibleOs.cpp similarity index 100% rename from swift/tools/autobuilder-diagnostics/IncompatibleOs.cpp rename to swift/tools/diagnostics/AutobuilderIncompatibleOs.cpp diff --git a/swift/tools/autobuilder-diagnostics/BUILD.bazel b/swift/tools/diagnostics/BUILD.bazel similarity index 72% rename from swift/tools/autobuilder-diagnostics/BUILD.bazel rename to swift/tools/diagnostics/BUILD.bazel index 8e76b553c73..e02d6aed13b 100644 --- a/swift/tools/autobuilder-diagnostics/BUILD.bazel +++ b/swift/tools/diagnostics/BUILD.bazel @@ -1,12 +1,12 @@ load("//swift:rules.bzl", "swift_cc_binary") swift_cc_binary( - name = "incompatible-os", - srcs = ["IncompatibleOs.cpp"], + name = "autobuilder-incompatible-os", + srcs = ["AutobuilderIncompatibleOs.cpp"], + # No restrictions (Windows allowed) + target_compatible_with = [], visibility = ["//swift:__subpackages__"], deps = [ "//swift/logging", ], - # No restrictions (Windows allowed) - target_compatible_with = [], ) From 679df1e61b3fff76d8586eca9e1eece0142d4f35 Mon Sep 17 00:00:00 2001 From: Alexandre Boulgakov Date: Fri, 16 Jun 2023 17:23:50 +0100 Subject: [PATCH 155/364] Swift: Add "autobuilder" on Windows that simply shows an error. --- swift/BUILD.bazel | 23 +++++++++++++++-------- swift/tools/BUILD.bazel | 3 ++- swift/tools/autobuild.cmd | 1 + 3 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 swift/tools/autobuild.cmd diff --git a/swift/BUILD.bazel b/swift/BUILD.bazel index 8ea073e991a..83dff3f8033 100644 --- a/swift/BUILD.bazel +++ b/swift/BUILD.bazel @@ -38,11 +38,15 @@ pkg_files( pkg_filegroup( name = "extractor-pack-generic", srcs = [ - ":dbscheme_files", ":manifest", - "//swift/downgrades", "//swift/tools", - ], + ] + select({ + "@platforms//os:windows": [], + "//conditions:default": [ + ":dbscheme_files", + "//swift/downgrades", + ], + }), visibility = ["//visibility:public"], ) @@ -80,11 +84,14 @@ pkg_files( pkg_filegroup( name = "extractor-pack-arch", - srcs = [ - ":extractor", - ":swift-test-sdk-arch", - ":resource-dir-arch", - ] + select({ + srcs = select({ + "@platforms//os:windows": [], + "//conditions:default": [ + ":extractor", + ":resource-dir-arch", + ":swift-test-sdk-arch", + ], + }) + select({ "@platforms//os:macos": [ ":xcode-autobuilder", ], diff --git a/swift/tools/BUILD.bazel b/swift/tools/BUILD.bazel index 8a3496a2700..ee834e543cc 100644 --- a/swift/tools/BUILD.bazel +++ b/swift/tools/BUILD.bazel @@ -19,8 +19,9 @@ sh_binary( pkg_files( name = "scripts", srcs = [ - ":identify-environment", + "autobuild.cmd", ":autobuild", + ":identify-environment", ":qltest", ], attributes = pkg_attributes(mode = "0755"), diff --git a/swift/tools/autobuild.cmd b/swift/tools/autobuild.cmd new file mode 100644 index 00000000000..fc90f9f2f05 --- /dev/null +++ b/swift/tools/autobuild.cmd @@ -0,0 +1 @@ +"%CODEQL_EXTRACTOR_SWIFT_ROOT%/tools/%CODEQL_PLATFORM%/autobuilder-incompatible-os.exe" From abc6d62b6fa29763a4536708f91690d927a7ec0f Mon Sep 17 00:00:00 2001 From: Alexandre Boulgakov Date: Fri, 16 Jun 2023 17:24:04 +0100 Subject: [PATCH 156/364] Swift: Use platform-specific Bazel config. --- .bazelrc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.bazelrc b/.bazelrc index e0ab5a34335..214258e775a 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,3 +1,9 @@ -build --repo_env=CC=clang --repo_env=CXX=clang++ --cxxopt="-std=c++20" +common --enable_platform_specific_config + +build --repo_env=CC=clang --repo_env=CXX=clang++ + +build:linux --cxxopt=-std=c++20 +build:macos --cxxopt=-std=c++20 --cpu=darwin_x86_64 +build:windows --cxxopt=/std:c++20 --cxxopt=/Zc:preprocessor try-import %workspace%/local.bazelrc From 000add206c7b68a3546fb575e215a3ba3d4dc8c9 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 16 Jun 2023 19:05:04 +0200 Subject: [PATCH 157/364] Revert "Exclude `cpp/overrun-write` from `cpp-security-extended.qls`" This reverts commit 3aaa649076d5b7e726452a480588698b62df75a6. --- cpp/ql/src/codeql-suites/cpp-security-extended.qls | 3 --- 1 file changed, 3 deletions(-) diff --git a/cpp/ql/src/codeql-suites/cpp-security-extended.qls b/cpp/ql/src/codeql-suites/cpp-security-extended.qls index 75deda24ef5..69c014c4c6f 100644 --- a/cpp/ql/src/codeql-suites/cpp-security-extended.qls +++ b/cpp/ql/src/codeql-suites/cpp-security-extended.qls @@ -3,6 +3,3 @@ - apply: security-extended-selectors.yml from: codeql/suite-helpers - apply: codeql-suites/exclude-slow-queries.yml -- exclude: - id: cpp/overrun-write - From 0bb67e45b330340e0fbddb13d2215065360d7fa2 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 16 Jun 2023 19:07:56 +0200 Subject: [PATCH 158/364] C++: lower the precision of `cpp/overrun-write` to exclude it from our query suites --- cpp/ql/src/Security/CWE/CWE-119/OverrunWriteProductFlow.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Security/CWE/CWE-119/OverrunWriteProductFlow.ql b/cpp/ql/src/Security/CWE/CWE-119/OverrunWriteProductFlow.ql index 0d8648aac0a..a9af2d08f51 100644 --- a/cpp/ql/src/Security/CWE/CWE-119/OverrunWriteProductFlow.ql +++ b/cpp/ql/src/Security/CWE/CWE-119/OverrunWriteProductFlow.ql @@ -5,7 +5,7 @@ * @kind path-problem * @problem.severity error * @security-severity 9.3 - * @precision medium + * @precision low * @id cpp/overrun-write * @tags reliability * security From 18f4b75f8ba2dee057ae44a4ca6dbaa7b54111da Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 6 Mar 2023 13:43:26 +0100 Subject: [PATCH 159/364] python: enable summaries from model This requires a change to the shared interface: Making `getNodeFromPath` public. This because Python is doing its own thing and identifying call-backs. --- .../python/dataflow/new/FlowSummary.qll | 70 +++++++++---------- .../data/internal/ApiGraphModels.qll | 9 +++ 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll b/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll index 5e82700bd0e..0fac6bfaedd 100644 --- a/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll +++ b/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll @@ -90,39 +90,37 @@ abstract class SummarizedCallable extends LibraryCallable, Impl::Public::Summari } class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack; -// // This gives access to getNodeFromPath, which is not constrained to `CallNode`s -// // as `resolvedSummaryBase` is. -// private import semmle.python.frameworks.data.internal.ApiGraphModels as AGM -// -// private class SummarizedCallableFromModel extends SummarizedCallable { -// string package; -// string type; -// string path; -// SummarizedCallableFromModel() { -// ModelOutput::relevantSummaryModel(package, type, path, _, _, _) and -// this = package + ";" + type + ";" + path -// } -// override CallCfgNode getACall() { -// exists(API::CallNode base | -// ModelOutput::resolvedSummaryBase(package, type, path, base) and -// result = base.getACall() -// ) -// } -// override ArgumentNode getACallback() { -// exists(API::Node base | -// base = AGM::getNodeFromPath(package, type, path) and -// result = base.getAValueReachableFromSource() -// ) -// } -// override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { -// exists(string kind | -// ModelOutput::relevantSummaryModel(package, type, path, input, output, kind) -// | -// kind = "value" and -// preservesValue = true -// or -// kind = "taint" and -// preservesValue = false -// ) -// } -// } + +private class SummarizedCallableFromModel extends SummarizedCallable { + string type; + string path; + + SummarizedCallableFromModel() { + ModelOutput::relevantSummaryModel(type, path, _, _, _) and + this = type + ";" + path + } + + override CallCfgNode getACall() { + exists(API::CallNode base | + ModelOutput::resolvedSummaryBase(type, path, base) and + result = base.getACall() + ) + } + + override ArgumentNode getACallback() { + exists(API::Node base | + ModelOutput::resolvedSummaryRefBase(type, path, base) and + result = base.getAValueReachableFromSource() + ) + } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + exists(string kind | ModelOutput::relevantSummaryModel(type, path, input, output, kind) | + kind = "value" and + preservesValue = true + or + kind = "taint" and + preservesValue = false + ) + } +} diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index 227f4ea22fb..6688ba36cd0 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -643,6 +643,15 @@ module ModelOutput { baseNode = getInvocationFromPath(type, path) } + /** + * Holds if a `baseNode` is an invocation identified by the `type,path` part of a summary row. + */ + cached + predicate resolvedSummaryRefBase(string type, string path, API::Node baseNode) { + summaryModel(type, path, _, _, _) and + baseNode = getNodeFromPath(type, path) + } + /** * Holds if `node` is seen as an instance of `type` due to a type definition * contributed by a CSV model. From 3cf9e3e69231a7d42d75cd2c8dca670bb20b6f54 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 20 Mar 2023 14:35:18 +0100 Subject: [PATCH 160/364] Py/js/ruby: sync files --- .../frameworks/data/internal/ApiGraphModels.qll | 9 +++++++++ .../ruby/frameworks/data/internal/ApiGraphModels.qll | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index 227f4ea22fb..6688ba36cd0 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -643,6 +643,15 @@ module ModelOutput { baseNode = getInvocationFromPath(type, path) } + /** + * Holds if a `baseNode` is an invocation identified by the `type,path` part of a summary row. + */ + cached + predicate resolvedSummaryRefBase(string type, string path, API::Node baseNode) { + summaryModel(type, path, _, _, _) and + baseNode = getNodeFromPath(type, path) + } + /** * Holds if `node` is seen as an instance of `type` due to a type definition * contributed by a CSV model. diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index 227f4ea22fb..6688ba36cd0 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -643,6 +643,15 @@ module ModelOutput { baseNode = getInvocationFromPath(type, path) } + /** + * Holds if a `baseNode` is an invocation identified by the `type,path` part of a summary row. + */ + cached + predicate resolvedSummaryRefBase(string type, string path, API::Node baseNode) { + summaryModel(type, path, _, _, _) and + baseNode = getNodeFromPath(type, path) + } + /** * Holds if `node` is seen as an instance of `type` due to a type definition * contributed by a CSV model. From 6554e804ddc9f5a6faaa2a72b9f9c9e68fdeff79 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 24 Mar 2023 09:48:31 +0100 Subject: [PATCH 161/364] python: add test for model summaries (but no summaries yet) --- .../NormalTaintTrackingTest.expected | 2 + .../NormalTaintTrackingTest.ql | 3 + .../model-summaries/TestSummaries.qll | 8 +++ .../model-summaries/model_summaries.py | 70 +++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.expected create mode 100644 python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.ql create mode 100644 python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll create mode 100644 python/ql/test/experimental/dataflow/model-summaries/model_summaries.py diff --git a/python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.expected b/python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.expected new file mode 100644 index 00000000000..3875da4e143 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.expected @@ -0,0 +1,2 @@ +missingAnnotationOnSink +failures diff --git a/python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.ql b/python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.ql new file mode 100644 index 00000000000..afb44b6b2ed --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.ql @@ -0,0 +1,3 @@ +import python +private import TestSummaries +import experimental.dataflow.TestUtil.NormalTaintTrackingTest diff --git a/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll b/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll new file mode 100644 index 00000000000..5069c406a60 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll @@ -0,0 +1,8 @@ +private import python +private import semmle.python.dataflow.new.FlowSummary +private import semmle.python.frameworks.data.ModelsAsData +private import semmle.python.ApiGraphs + +private class StepsFromModel extends ModelInput::SummaryModelCsv { + override predicate row(string row) { none() } +} diff --git a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py new file mode 100644 index 00000000000..498d445efdf --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py @@ -0,0 +1,70 @@ + +import sys +import os + +sys.path.append(os.path.dirname(os.path.dirname((__file__)))) +from testlib import expects + +# These are defined so that we can evaluate the test code. +NONSOURCE = "not a source" +SOURCE = "source" + + +def is_source(x): + return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j + + +def SINK(x): + if is_source(x): + print("OK") + else: + print("Unexpected flow", x) + + +def SINK_F(x): + if is_source(x): + print("Unexpected flow", x) + else: + print("OK") + + +from Foo import identity + +# Simple summary +tainted = identity(SOURCE) +SINK(tainted) # $ MISSING: flow="SOURCE, l:-1 -> tainted" + +# Lambda summary +tainted_lambda = apply_lambda(lambda x: x + 1, SOURCE) +SINK(tainted_lambda) # $ MISSING: flow="SOURCE, l:-1 -> tainted_lambda" + +# A lambda that breaks the flow +untainted_lambda = apply_lambda(lambda x: 1, SOURCE) +SINK_F(untainted_lambda) + +# Collection summaries +tainted_list = my_reversed([SOURCE]) +SINK(tainted_list[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_list[0]" + +# Complex summaries +def add_colon(x): + return x + ":" + +tainted_mapped = list_map(add_colon, [SOURCE]) +SINK(tainted_mapped[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped[0]" + +def explicit_identity(x): + return x + +tainted_mapped_explicit = list_map(explicit_identity, [SOURCE]) +SINK(tainted_mapped_explicit[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" + +tainted_mapped_summary = list_map(identity, [SOURCE]) +SINK(tainted_mapped_summary[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" + +tainted_list = append_to_list([], SOURCE) +SINK(tainted_list[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_list[0]" + +from json import my_loads as json_loads +tainted_resultlist = json_loads(SOURCE) +SINK(tainted_resultlist[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_resultlist[0]" From 229641070fd65a891fd2055fcea595dca143246f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Sun, 18 Jun 2023 22:01:47 +0200 Subject: [PATCH 162/364] python: rename summaries --- .../model-summaries/model_summaries.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py index 498d445efdf..23cc4990aba 100644 --- a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py +++ b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py @@ -28,43 +28,43 @@ def SINK_F(x): print("OK") -from Foo import identity +from Foo import MS_identity # Simple summary -tainted = identity(SOURCE) +tainted = MS_identity(SOURCE) SINK(tainted) # $ MISSING: flow="SOURCE, l:-1 -> tainted" # Lambda summary -tainted_lambda = apply_lambda(lambda x: x + 1, SOURCE) +tainted_lambda = MS_apply_lambda(lambda x: x + 1, SOURCE) SINK(tainted_lambda) # $ MISSING: flow="SOURCE, l:-1 -> tainted_lambda" # A lambda that breaks the flow -untainted_lambda = apply_lambda(lambda x: 1, SOURCE) +untainted_lambda = MS_apply_lambda(lambda x: 1, SOURCE) SINK_F(untainted_lambda) # Collection summaries -tainted_list = my_reversed([SOURCE]) +tainted_list = MS_reversed([SOURCE]) SINK(tainted_list[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_list[0]" # Complex summaries def add_colon(x): return x + ":" -tainted_mapped = list_map(add_colon, [SOURCE]) +tainted_mapped = MS_list_map(add_colon, [SOURCE]) SINK(tainted_mapped[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped[0]" def explicit_identity(x): return x -tainted_mapped_explicit = list_map(explicit_identity, [SOURCE]) +tainted_mapped_explicit = MS_list_map(explicit_identity, [SOURCE]) SINK(tainted_mapped_explicit[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" -tainted_mapped_summary = list_map(identity, [SOURCE]) +tainted_mapped_summary = MS_list_map(MS_identity, [SOURCE]) SINK(tainted_mapped_summary[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" -tainted_list = append_to_list([], SOURCE) +tainted_list = MS_append_to_list([], SOURCE) SINK(tainted_list[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_list[0]" -from json import my_loads as json_loads +from json import MS_loads as json_loads tainted_resultlist = json_loads(SOURCE) SINK(tainted_resultlist[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_resultlist[0]" From 433fc680ecb608b5db1a2ea9305acba99ba2d852 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 19 Jun 2023 10:17:40 +0200 Subject: [PATCH 163/364] Apply suggestions from code review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- csharp/ql/src/change-notes/2023-06-16-zipslip-rename.md | 2 +- go/ql/src/change-notes/2023-06-16-zipslip-rename.md | 2 +- java/ql/src/change-notes/2023-06-16-zipslip-rename.md | 2 +- javascript/ql/src/change-notes/2023-06-16-zipslip-rename.md | 2 +- python/ql/src/change-notes/2023-06-16-zipslip-rename.md | 2 +- ruby/ql/src/change-notes/2023-06-16-zipslip-rename.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/csharp/ql/src/change-notes/2023-06-16-zipslip-rename.md b/csharp/ql/src/change-notes/2023-06-16-zipslip-rename.md index 2816d74945c..3c13e6da67a 100644 --- a/csharp/ql/src/change-notes/2023-06-16-zipslip-rename.md +++ b/csharp/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -1,4 +1,4 @@ --- category: fix --- -* The query "Arbitrary file write during zip extraction ("Zip Slip")" (`cs/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". +* The query "Arbitrary file write during zip extraction ("Zip Slip")" (`cs/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")." diff --git a/go/ql/src/change-notes/2023-06-16-zipslip-rename.md b/go/ql/src/change-notes/2023-06-16-zipslip-rename.md index 9e9d1483ad6..72913f37c06 100644 --- a/go/ql/src/change-notes/2023-06-16-zipslip-rename.md +++ b/go/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -1,4 +1,4 @@ --- category: fix --- -* The query "Arbitrary file write during zip extraction ("zip slip")" (`go/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". +* The query "Arbitrary file write during zip extraction ("zip slip")" (`go/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")." diff --git a/java/ql/src/change-notes/2023-06-16-zipslip-rename.md b/java/ql/src/change-notes/2023-06-16-zipslip-rename.md index 39316e46f5d..fa1343317ba 100644 --- a/java/ql/src/change-notes/2023-06-16-zipslip-rename.md +++ b/java/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -1,4 +1,4 @@ --- category: fix --- -* The query "Arbitrary file write during archive extraction ("Zip Slip")" (`java/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". +* The query "Arbitrary file write during archive extraction ("Zip Slip")" (`java/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")." diff --git a/javascript/ql/src/change-notes/2023-06-16-zipslip-rename.md b/javascript/ql/src/change-notes/2023-06-16-zipslip-rename.md index 0d866964347..3a0654e642e 100644 --- a/javascript/ql/src/change-notes/2023-06-16-zipslip-rename.md +++ b/javascript/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -1,4 +1,4 @@ --- category: fix --- -* The query "Arbitrary file write during zip extraction ("Zip Slip")" (`js/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". +* The query "Arbitrary file write during zip extraction ("Zip Slip")" (`js/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")." diff --git a/python/ql/src/change-notes/2023-06-16-zipslip-rename.md b/python/ql/src/change-notes/2023-06-16-zipslip-rename.md index 50313eb7d27..4d4d4db15c3 100644 --- a/python/ql/src/change-notes/2023-06-16-zipslip-rename.md +++ b/python/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -1,4 +1,4 @@ --- category: fix --- -* The query "Arbitrary file write during archive extraction ("Zip Slip")" (`py/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". +* The query "Arbitrary file write during archive extraction ("Zip Slip")" (`py/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")." diff --git a/ruby/ql/src/change-notes/2023-06-16-zipslip-rename.md b/ruby/ql/src/change-notes/2023-06-16-zipslip-rename.md index 8e56e960ec4..eeb9c5254bb 100644 --- a/ruby/ql/src/change-notes/2023-06-16-zipslip-rename.md +++ b/ruby/ql/src/change-notes/2023-06-16-zipslip-rename.md @@ -1,4 +1,4 @@ --- category: fix --- -* The experimental query "Arbitrary file write during zipfile/tarfile extraction" (`ruby/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")". +* The experimental query "Arbitrary file write during zipfile/tarfile extraction" (`ruby/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")." From 3c4d938cf1c91572d4d43f8e09653c1da34f751a Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 19 Jun 2023 10:18:02 +0200 Subject: [PATCH 164/364] Apply code review suggestions. Co-authored-by: Asger F --- csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp | 7 +++---- go/ql/src/Security/CWE-022/ZipSlip.qhelp | 6 +++--- java/ql/src/Security/CWE/CWE-022/ZipSlip.qhelp | 7 +++---- javascript/ql/src/Security/CWE-022/ZipSlip.qhelp | 6 +++--- python/ql/src/experimental/Security/CWE-022/ZipSlip.qhelp | 7 +++---- ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.qhelp | 7 +++---- 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp b/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp index e1e2974ed4f..a1f39d27b8c 100644 --- a/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp +++ b/csharp/ql/src/Security Features/CWE-022/ZipSlip.qhelp @@ -3,10 +3,9 @@ "qhelp.dtd"> -

    Accessing filesystem paths built from the name of an archive entry without validating that the -destination file path is within the destination directory can allow an attacker to access -unexpected resources, due to the possible presence of directory traversal elements (..) in -archive paths.

    +

    Extracting files from a malicious zip file, or similar type of archive, +is at risk of directory traversal attacks if filenames from the archive are +not properly validated.

    Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain diff --git a/go/ql/src/Security/CWE-022/ZipSlip.qhelp b/go/ql/src/Security/CWE-022/ZipSlip.qhelp index 1c47eac9a53..ecea2eaeec9 100644 --- a/go/ql/src/Security/CWE-022/ZipSlip.qhelp +++ b/go/ql/src/Security/CWE-022/ZipSlip.qhelp @@ -5,9 +5,9 @@

    -Accessing filesystem paths built from the name of an archive entry without validating that the -destination file path is within the destination directory can allow an attacker to access -unexpected resources, due to the possible presence of directory traversal elements (..) in +Extracting files from a malicious zip file, or similar type of archive, +is at risk of directory traversal attacks if filenames from the archive are +not properly validated. archive paths.

    diff --git a/java/ql/src/Security/CWE/CWE-022/ZipSlip.qhelp b/java/ql/src/Security/CWE/CWE-022/ZipSlip.qhelp index 726b2d15cb6..2caf0ccc8b0 100644 --- a/java/ql/src/Security/CWE/CWE-022/ZipSlip.qhelp +++ b/java/ql/src/Security/CWE/CWE-022/ZipSlip.qhelp @@ -3,10 +3,9 @@ "qhelp.dtd"> -

    Accessing filesystem paths built from the name of an archive entry without validating that the -destination file path is within the destination directory can allow an attacker to access -unexpected resources, due to the possible presence of directory traversal elements (..) in -archive paths.

    +

    Extracting files from a malicious zip file, or similar type of archive, +is at risk of directory traversal attacks if filenames from the archive are +not properly validated.

    Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain diff --git a/javascript/ql/src/Security/CWE-022/ZipSlip.qhelp b/javascript/ql/src/Security/CWE-022/ZipSlip.qhelp index bbb3824e41e..2318ad859f0 100644 --- a/javascript/ql/src/Security/CWE-022/ZipSlip.qhelp +++ b/javascript/ql/src/Security/CWE-022/ZipSlip.qhelp @@ -4,9 +4,9 @@ -

    Accessing filesystem paths built from the name of an archive entry without validating that the -destination file path is within the destination directory can allow an attacker to access -unexpected resources, due to the possible presence of directory traversal elements (..) in +

    Extracting files from a malicious zip file, or similar type of archive, +is at risk of directory traversal attacks if filenames from the archive are +not properly validated. archive paths.

    Zip archives contain archive entries representing each file in the archive. These entries diff --git a/python/ql/src/experimental/Security/CWE-022/ZipSlip.qhelp b/python/ql/src/experimental/Security/CWE-022/ZipSlip.qhelp index dfd563ea19b..4afb7cc9a2a 100644 --- a/python/ql/src/experimental/Security/CWE-022/ZipSlip.qhelp +++ b/python/ql/src/experimental/Security/CWE-022/ZipSlip.qhelp @@ -4,10 +4,9 @@ -

    Accessing filesystem paths built from the name of an archive entry without validating that the -destination file path is within the destination directory can allow an attacker to access -unexpected resources, due to the possible presence of directory traversal elements (..) in -archive paths.

    +

    Extracting files from a malicious zip file, or similar type of archive, +is at risk of directory traversal attacks if filenames from the archive are +not properly validated.

    Zip archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain diff --git a/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.qhelp b/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.qhelp index 2794db7efbd..7d7435ee907 100644 --- a/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.qhelp +++ b/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.qhelp @@ -4,10 +4,9 @@ -

    Accessing filesystem paths built from the name of an archive entry without validating that the -destination file path is within the destination directory can allow an attacker to access -unexpected resources, due to the possible presence of directory traversal elements (..) in -archive paths.

    +

    Extracting files from a malicious zip file, or similar type of archive, +is at risk of directory traversal attacks if filenames from the archive are +not properly validated.

    Tar archives contain archive entries representing each file in the archive. These entries include a file path for the entry, but these file paths are not restricted and may contain From 8f6d2ed2f9045420e8331852f1b7e1942d9775fc Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 19 Jun 2023 10:27:41 +0200 Subject: [PATCH 165/364] Adjust ZipSlip query description according to review suggestions. --- csharp/ql/src/Security Features/CWE-022/ZipSlip.ql | 4 ++-- go/ql/src/Security/CWE-022/ZipSlip.ql | 4 ++-- java/ql/src/Security/CWE/CWE-022/ZipSlip.ql | 4 ++-- javascript/ql/src/Security/CWE-022/ZipSlip.ql | 4 ++-- python/ql/src/experimental/Security/CWE-022/ZipSlip.ql | 4 ++-- ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.ql | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql b/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql index 25a1e9bcd19..2e4d59aaf7e 100644 --- a/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql +++ b/csharp/ql/src/Security Features/CWE-022/ZipSlip.ql @@ -1,8 +1,8 @@ /** * @name Arbitrary file access during archive extraction ("Zip Slip") - * @description Accessing filesystem paths built from the name of an archive entry without + * @description Extracting files from a malicious ZIP file, or similar type of archive, without * validating that the destination file path is within the destination directory - * can allow an attacker to access unexpected resources. + * can allow an attacker to unexpectedly gain access to resources. * @kind path-problem * @id cs/zipslip * @problem.severity error diff --git a/go/ql/src/Security/CWE-022/ZipSlip.ql b/go/ql/src/Security/CWE-022/ZipSlip.ql index 27c18248ad5..5cfb3998f4d 100644 --- a/go/ql/src/Security/CWE-022/ZipSlip.ql +++ b/go/ql/src/Security/CWE-022/ZipSlip.ql @@ -1,8 +1,8 @@ /** * @name Arbitrary file access during archive extraction ("Zip Slip") - * @description Accessing filesystem paths built from the name of an archive entry without + * @description Extracting files from a malicious ZIP file, or similar type of archive, without * validating that the destination file path is within the destination directory - * can allow an attacker to access unexpected resources. + * can allow an attacker to unexpectedly gain access to resources. * @kind path-problem * @id go/zipslip * @problem.severity error diff --git a/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql b/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql index 2c48ecb2aa1..0d165a73521 100644 --- a/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql +++ b/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql @@ -1,8 +1,8 @@ /** * @name Arbitrary file access during archive extraction ("Zip Slip") - * @description Accessing filesystem paths built from the name of an archive entry without + * @description Extracting files from a malicious ZIP file, or similar type of archive, without * validating that the destination file path is within the destination directory - * can allow an attacker to access unexpected resources. + * can allow an attacker to unexpectedly gain access to resources. * @kind path-problem * @id java/zipslip * @problem.severity error diff --git a/javascript/ql/src/Security/CWE-022/ZipSlip.ql b/javascript/ql/src/Security/CWE-022/ZipSlip.ql index f9c468c388a..aef13830eb1 100644 --- a/javascript/ql/src/Security/CWE-022/ZipSlip.ql +++ b/javascript/ql/src/Security/CWE-022/ZipSlip.ql @@ -1,8 +1,8 @@ /** * @name Arbitrary file access during archive extraction ("Zip Slip") - * @description Accessing filesystem paths built from the name of an archive entry without + * @description Extracting files from a malicious ZIP file, or similar type of archive, without * validating that the destination file path is within the destination directory - * can allow an attacker to access unexpected resources. + * can allow an attacker to unexpectedly gain access to resources. * @kind path-problem * @id js/zipslip * @problem.severity error diff --git a/python/ql/src/experimental/Security/CWE-022/ZipSlip.ql b/python/ql/src/experimental/Security/CWE-022/ZipSlip.ql index b00214cfe68..eba8da087b3 100644 --- a/python/ql/src/experimental/Security/CWE-022/ZipSlip.ql +++ b/python/ql/src/experimental/Security/CWE-022/ZipSlip.ql @@ -1,8 +1,8 @@ /** * @name Arbitrary file access during archive extraction ("Zip Slip") - * @description Accessing filesystem paths built from the name of an archive entry without + * @description Extracting files from a malicious ZIP file, or similar type of archive, without * validating that the destination file path is within the destination directory - * can allow an attacker to access unexpected resources. + * can allow an attacker to unexpectedly gain access to resources. * @kind path-problem * @id py/zipslip * @problem.severity error diff --git a/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.ql b/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.ql index 709e89f98e8..329f4b89977 100644 --- a/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.ql +++ b/ruby/ql/src/experimental/cwe-022-zipslip/ZipSlip.ql @@ -1,8 +1,8 @@ /** * @name Arbitrary file access during archive extraction ("Zip Slip") - * @description Accessing filesystem paths built from the name of an archive entry without + * @description Extracting files from a malicious ZIP file, or similar type of archive, without * validating that the destination file path is within the destination directory - * can allow an attacker to access unexpected resources. + * can allow an attacker to unexpectedly gain access to resources. * @kind path-problem * @id rb/zip-slip * @problem.severity error From 6a84e6cbfd285feb9fb4fde4395782a10532b2c0 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 19 Jun 2023 10:28:10 +0200 Subject: [PATCH 166/364] Add the merged `PathGraph` to all copies of the `InlineFlowTest` library --- csharp/ql/test/TestUtilities/InlineFlowTest.qll | 12 +++++++++--- go/ql/test/TestUtilities/InlineFlowTest.qll | 11 +++++++++++ java/ql/test/TestUtilities/InlineFlowTest.qll | 12 ++++++++++++ ruby/ql/test/TestUtilities/InlineFlowTest.qll | 4 ++-- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/csharp/ql/test/TestUtilities/InlineFlowTest.qll b/csharp/ql/test/TestUtilities/InlineFlowTest.qll index dc95063f03f..718752a978a 100644 --- a/csharp/ql/test/TestUtilities/InlineFlowTest.qll +++ b/csharp/ql/test/TestUtilities/InlineFlowTest.qll @@ -6,10 +6,10 @@ * import csharp * import TestUtilities.InlineFlowTest * import DefaultFlowTest - * import ValueFlow::PathGraph + * import PathGraph * - * from ValueFlow::PathNode source, ValueFlow::PathNode sink - * where ValueFlow::flowPath(source, sink) + * from PathNode source, PathNode sink + * where flowPath(source, sink) * select sink, source, sink, "$@", source, source.toString() * * ``` @@ -101,6 +101,12 @@ module FlowTest + import DataFlow::MergePathGraph + + predicate flowPath(PathNode source, PathNode sink) { + ValueFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) or + TaintFlow::flowPath(source.asPathNode2(), sink.asPathNode2()) + } } module DefaultFlowTest = FlowTest; diff --git a/go/ql/test/TestUtilities/InlineFlowTest.qll b/go/ql/test/TestUtilities/InlineFlowTest.qll index f8d54c82f3f..4f3cfc7599a 100644 --- a/go/ql/test/TestUtilities/InlineFlowTest.qll +++ b/go/ql/test/TestUtilities/InlineFlowTest.qll @@ -6,6 +6,11 @@ * import go * import TestUtilities.InlineFlowTest * import DefaultFlowTest + * import PathGraph + * + * from PathNode source, PathNode sink + * where flowPath(source, sink) + * select sink, source, sink, "$@", source, source.toString() * ``` * * To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. @@ -88,6 +93,12 @@ module FlowTest + import DataFlow::MergePathGraph + + predicate flowPath(PathNode source, PathNode sink) { + ValueFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) or + TaintFlow::flowPath(source.asPathNode2(), sink.asPathNode2()) + } } module DefaultFlowTest = FlowTest; diff --git a/java/ql/test/TestUtilities/InlineFlowTest.qll b/java/ql/test/TestUtilities/InlineFlowTest.qll index 6f344c5074e..45ba10ee149 100644 --- a/java/ql/test/TestUtilities/InlineFlowTest.qll +++ b/java/ql/test/TestUtilities/InlineFlowTest.qll @@ -6,6 +6,12 @@ * import java * import TestUtilities.InlineFlowTest * import DefaultFlowTest + * import PathGraph + * + * from PathNode source, PathNode sink + * where flowPath(source, sink) + * select sink, source, sink, "$@", source, source.toString() + * ``` * * To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. @@ -95,6 +101,12 @@ module FlowTest + import DataFlow::MergePathGraph + + predicate flowPath(PathNode source, PathNode sink) { + ValueFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) or + TaintFlow::flowPath(source.asPathNode2(), sink.asPathNode2()) + } } module DefaultFlowTest = FlowTest; diff --git a/ruby/ql/test/TestUtilities/InlineFlowTest.qll b/ruby/ql/test/TestUtilities/InlineFlowTest.qll index af83862803c..cefd109f0a9 100644 --- a/ruby/ql/test/TestUtilities/InlineFlowTest.qll +++ b/ruby/ql/test/TestUtilities/InlineFlowTest.qll @@ -7,8 +7,8 @@ * import DefaultFlowTest * import PathGraph * - * from ValueFlow::PathNode source, ValueFlow::PathNode sink - * where ValueFlow::flowPath(source, sink) + * from PathNode source, PathNode sink + * where flowPath(source, sink) * select sink, source, sink, "$@", source, source.toString() * ``` * From b420455e2baf315252a2cff980484f9fb2490f43 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 19 Jun 2023 10:28:54 +0200 Subject: [PATCH 167/364] C#: Update `InlineFlowTest`s to use the merged path graph --- .../dataflow/fields/FieldFlow.expected | 1095 +++++++++++++++++ .../dataflow/fields/FieldFlow.ql | 6 +- .../dataflow/operators/operatorFlow.expected | 90 ++ .../dataflow/operators/operatorFlow.ql | 6 +- .../dataflow/patterns/PatternFlow.ql | 6 +- .../dataflow/tuples/Tuples.expected | 228 ++++ .../library-tests/dataflow/tuples/Tuples.ql | 6 +- 7 files changed, 1425 insertions(+), 12 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index a0d9a917702..7466125341d 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -2,1100 +2,2195 @@ failures testFailures edges | A.cs:5:17:5:28 | call to method Source : C | A.cs:6:24:6:24 | access to local variable c : C | +| A.cs:5:17:5:28 | call to method Source : C | A.cs:6:24:6:24 | access to local variable c : C | +| A.cs:6:17:6:25 | call to method Make : B [field c] : C | A.cs:7:14:7:14 | access to local variable b : B [field c] : C | | A.cs:6:17:6:25 | call to method Make : B [field c] : C | A.cs:7:14:7:14 | access to local variable b : B [field c] : C | | A.cs:6:24:6:24 | access to local variable c : C | A.cs:6:17:6:25 | call to method Make : B [field c] : C | +| A.cs:6:24:6:24 | access to local variable c : C | A.cs:6:17:6:25 | call to method Make : B [field c] : C | +| A.cs:6:24:6:24 | access to local variable c : C | A.cs:147:32:147:32 | c : C | | A.cs:6:24:6:24 | access to local variable c : C | A.cs:147:32:147:32 | c : C | | A.cs:7:14:7:14 | access to local variable b : B [field c] : C | A.cs:7:14:7:16 | access to field c | +| A.cs:7:14:7:14 | access to local variable b : B [field c] : C | A.cs:7:14:7:16 | access to field c | +| A.cs:13:9:13:9 | [post] access to local variable b : B [field c] : C1 | A.cs:14:14:14:14 | access to local variable b : B [field c] : C1 | | A.cs:13:9:13:9 | [post] access to local variable b : B [field c] : C1 | A.cs:14:14:14:14 | access to local variable b : B [field c] : C1 | | A.cs:13:15:13:29 | call to method Source : C1 | A.cs:13:9:13:9 | [post] access to local variable b : B [field c] : C1 | +| A.cs:13:15:13:29 | call to method Source : C1 | A.cs:13:9:13:9 | [post] access to local variable b : B [field c] : C1 | +| A.cs:13:15:13:29 | call to method Source : C1 | A.cs:145:27:145:27 | c : C1 | | A.cs:13:15:13:29 | call to method Source : C1 | A.cs:145:27:145:27 | c : C1 | | A.cs:14:14:14:14 | access to local variable b : B [field c] : C1 | A.cs:14:14:14:20 | call to method Get | +| A.cs:14:14:14:14 | access to local variable b : B [field c] : C1 | A.cs:14:14:14:20 | call to method Get | +| A.cs:14:14:14:14 | access to local variable b : B [field c] : C1 | A.cs:146:18:146:20 | this : B [field c] : C1 | | A.cs:14:14:14:14 | access to local variable b : B [field c] : C1 | A.cs:146:18:146:20 | this : B [field c] : C1 | | A.cs:15:15:15:35 | object creation of type B : B [field c] : C | A.cs:15:14:15:42 | call to method Get | +| A.cs:15:15:15:35 | object creation of type B : B [field c] : C | A.cs:15:14:15:42 | call to method Get | +| A.cs:15:15:15:35 | object creation of type B : B [field c] : C | A.cs:146:18:146:20 | this : B [field c] : C | | A.cs:15:15:15:35 | object creation of type B : B [field c] : C | A.cs:146:18:146:20 | this : B [field c] : C | | A.cs:15:21:15:34 | call to method Source : C | A.cs:15:15:15:35 | object creation of type B : B [field c] : C | +| A.cs:15:21:15:34 | call to method Source : C | A.cs:15:15:15:35 | object creation of type B : B [field c] : C | +| A.cs:15:21:15:34 | call to method Source : C | A.cs:141:20:141:20 | c : C | | A.cs:15:21:15:34 | call to method Source : C | A.cs:141:20:141:20 | c : C | | A.cs:22:14:22:38 | call to method SetOnB : B [field c] : C2 | A.cs:24:14:24:15 | access to local variable b2 : B [field c] : C2 | +| A.cs:22:14:22:38 | call to method SetOnB : B [field c] : C2 | A.cs:24:14:24:15 | access to local variable b2 : B [field c] : C2 | +| A.cs:22:25:22:37 | call to method Source : C2 | A.cs:22:14:22:38 | call to method SetOnB : B [field c] : C2 | | A.cs:22:25:22:37 | call to method Source : C2 | A.cs:22:14:22:38 | call to method SetOnB : B [field c] : C2 | | A.cs:22:25:22:37 | call to method Source : C2 | A.cs:42:29:42:29 | c : C2 | +| A.cs:22:25:22:37 | call to method Source : C2 | A.cs:42:29:42:29 | c : C2 | +| A.cs:24:14:24:15 | access to local variable b2 : B [field c] : C2 | A.cs:24:14:24:17 | access to field c | | A.cs:24:14:24:15 | access to local variable b2 : B [field c] : C2 | A.cs:24:14:24:17 | access to field c | | A.cs:31:14:31:42 | call to method SetOnBWrap : B [field c] : C2 | A.cs:33:14:33:15 | access to local variable b2 : B [field c] : C2 | +| A.cs:31:14:31:42 | call to method SetOnBWrap : B [field c] : C2 | A.cs:33:14:33:15 | access to local variable b2 : B [field c] : C2 | +| A.cs:31:29:31:41 | call to method Source : C2 | A.cs:31:14:31:42 | call to method SetOnBWrap : B [field c] : C2 | | A.cs:31:29:31:41 | call to method Source : C2 | A.cs:31:14:31:42 | call to method SetOnBWrap : B [field c] : C2 | | A.cs:31:29:31:41 | call to method Source : C2 | A.cs:36:33:36:33 | c : C2 | +| A.cs:31:29:31:41 | call to method Source : C2 | A.cs:36:33:36:33 | c : C2 | +| A.cs:33:14:33:15 | access to local variable b2 : B [field c] : C2 | A.cs:33:14:33:17 | access to field c | | A.cs:33:14:33:15 | access to local variable b2 : B [field c] : C2 | A.cs:33:14:33:17 | access to field c | | A.cs:36:33:36:33 | c : C2 | A.cs:38:29:38:29 | access to parameter c : C2 | +| A.cs:36:33:36:33 | c : C2 | A.cs:38:29:38:29 | access to parameter c : C2 | +| A.cs:38:18:38:30 | call to method SetOnB : B [field c] : C2 | A.cs:39:16:39:28 | ... ? ... : ... : B [field c] : C2 | | A.cs:38:18:38:30 | call to method SetOnB : B [field c] : C2 | A.cs:39:16:39:28 | ... ? ... : ... : B [field c] : C2 | | A.cs:38:29:38:29 | access to parameter c : C2 | A.cs:38:18:38:30 | call to method SetOnB : B [field c] : C2 | +| A.cs:38:29:38:29 | access to parameter c : C2 | A.cs:38:18:38:30 | call to method SetOnB : B [field c] : C2 | +| A.cs:38:29:38:29 | access to parameter c : C2 | A.cs:42:29:42:29 | c : C2 | | A.cs:38:29:38:29 | access to parameter c : C2 | A.cs:42:29:42:29 | c : C2 | | A.cs:42:29:42:29 | c : C2 | A.cs:47:20:47:20 | access to parameter c : C2 | +| A.cs:42:29:42:29 | c : C2 | A.cs:47:20:47:20 | access to parameter c : C2 | +| A.cs:47:13:47:14 | [post] access to local variable b2 : B [field c] : C2 | A.cs:48:20:48:21 | access to local variable b2 : B [field c] : C2 | | A.cs:47:13:47:14 | [post] access to local variable b2 : B [field c] : C2 | A.cs:48:20:48:21 | access to local variable b2 : B [field c] : C2 | | A.cs:47:20:47:20 | access to parameter c : C2 | A.cs:47:13:47:14 | [post] access to local variable b2 : B [field c] : C2 | +| A.cs:47:20:47:20 | access to parameter c : C2 | A.cs:47:13:47:14 | [post] access to local variable b2 : B [field c] : C2 | +| A.cs:47:20:47:20 | access to parameter c : C2 | A.cs:145:27:145:27 | c : C2 | | A.cs:47:20:47:20 | access to parameter c : C2 | A.cs:145:27:145:27 | c : C2 | | A.cs:55:17:55:28 | call to method Source : A | A.cs:57:16:57:16 | access to local variable a : A | +| A.cs:55:17:55:28 | call to method Source : A | A.cs:57:16:57:16 | access to local variable a : A | +| A.cs:57:9:57:10 | [post] access to local variable c1 : C1 [field a] : A | A.cs:58:12:58:13 | access to local variable c1 : C1 [field a] : A | | A.cs:57:9:57:10 | [post] access to local variable c1 : C1 [field a] : A | A.cs:58:12:58:13 | access to local variable c1 : C1 [field a] : A | | A.cs:57:16:57:16 | access to local variable a : A | A.cs:57:9:57:10 | [post] access to local variable c1 : C1 [field a] : A | +| A.cs:57:16:57:16 | access to local variable a : A | A.cs:57:9:57:10 | [post] access to local variable c1 : C1 [field a] : A | +| A.cs:58:12:58:13 | access to local variable c1 : C1 [field a] : A | A.cs:60:22:60:22 | c : C1 [field a] : A | | A.cs:58:12:58:13 | access to local variable c1 : C1 [field a] : A | A.cs:60:22:60:22 | c : C1 [field a] : A | | A.cs:60:22:60:22 | c : C1 [field a] : A | A.cs:64:19:64:23 | (...) ... : C1 [field a] : A | +| A.cs:60:22:60:22 | c : C1 [field a] : A | A.cs:64:19:64:23 | (...) ... : C1 [field a] : A | +| A.cs:64:19:64:23 | (...) ... : C1 [field a] : A | A.cs:64:18:64:26 | access to field a | | A.cs:64:19:64:23 | (...) ... : C1 [field a] : A | A.cs:64:18:64:26 | access to field a | | A.cs:83:9:83:9 | [post] access to parameter b : B [field c] : C | A.cs:88:12:88:12 | [post] access to local variable b : B [field c] : C | +| A.cs:83:9:83:9 | [post] access to parameter b : B [field c] : C | A.cs:88:12:88:12 | [post] access to local variable b : B [field c] : C | +| A.cs:83:15:83:26 | call to method Source : C | A.cs:83:9:83:9 | [post] access to parameter b : B [field c] : C | | A.cs:83:15:83:26 | call to method Source : C | A.cs:83:9:83:9 | [post] access to parameter b : B [field c] : C | | A.cs:83:15:83:26 | call to method Source : C | A.cs:145:27:145:27 | c : C | +| A.cs:83:15:83:26 | call to method Source : C | A.cs:145:27:145:27 | c : C | +| A.cs:88:12:88:12 | [post] access to local variable b : B [field c] : C | A.cs:89:14:89:14 | access to local variable b : B [field c] : C | | A.cs:88:12:88:12 | [post] access to local variable b : B [field c] : C | A.cs:89:14:89:14 | access to local variable b : B [field c] : C | | A.cs:89:14:89:14 | access to local variable b : B [field c] : C | A.cs:89:14:89:16 | access to field c | +| A.cs:89:14:89:14 | access to local variable b : B [field c] : C | A.cs:89:14:89:16 | access to field c | +| A.cs:95:20:95:20 | b : B | A.cs:97:13:97:13 | access to parameter b : B | | A.cs:95:20:95:20 | b : B | A.cs:97:13:97:13 | access to parameter b : B | | A.cs:97:13:97:13 | [post] access to parameter b : B [field c] : C | A.cs:98:22:98:43 | ... ? ... : ... : B [field c] : C | +| A.cs:97:13:97:13 | [post] access to parameter b : B [field c] : C | A.cs:98:22:98:43 | ... ? ... : ... : B [field c] : C | +| A.cs:97:13:97:13 | [post] access to parameter b : B [field c] : C | A.cs:105:23:105:23 | [post] access to local variable b : B [field c] : C | | A.cs:97:13:97:13 | [post] access to parameter b : B [field c] : C | A.cs:105:23:105:23 | [post] access to local variable b : B [field c] : C | | A.cs:97:13:97:13 | access to parameter b : B | A.cs:98:22:98:43 | ... ? ... : ... : B | +| A.cs:97:13:97:13 | access to parameter b : B | A.cs:98:22:98:43 | ... ? ... : ... : B | +| A.cs:97:19:97:32 | call to method Source : C | A.cs:97:13:97:13 | [post] access to parameter b : B [field c] : C | | A.cs:97:19:97:32 | call to method Source : C | A.cs:97:13:97:13 | [post] access to parameter b : B [field c] : C | | A.cs:98:13:98:16 | [post] this access : D [field b, field c] : C | A.cs:105:17:105:29 | object creation of type D : D [field b, field c] : C | +| A.cs:98:13:98:16 | [post] this access : D [field b, field c] : C | A.cs:105:17:105:29 | object creation of type D : D [field b, field c] : C | +| A.cs:98:13:98:16 | [post] this access : D [field b] : B | A.cs:105:17:105:29 | object creation of type D : D [field b] : B | | A.cs:98:13:98:16 | [post] this access : D [field b] : B | A.cs:105:17:105:29 | object creation of type D : D [field b] : B | | A.cs:98:22:98:43 | ... ? ... : ... : B | A.cs:98:13:98:16 | [post] this access : D [field b] : B | | A.cs:98:22:98:43 | ... ? ... : ... : B | A.cs:98:13:98:16 | [post] this access : D [field b] : B | +| A.cs:98:22:98:43 | ... ? ... : ... : B | A.cs:98:13:98:16 | [post] this access : D [field b] : B | +| A.cs:98:22:98:43 | ... ? ... : ... : B | A.cs:98:13:98:16 | [post] this access : D [field b] : B | +| A.cs:98:22:98:43 | ... ? ... : ... : B [field c] : C | A.cs:98:13:98:16 | [post] this access : D [field b, field c] : C | | A.cs:98:22:98:43 | ... ? ... : ... : B [field c] : C | A.cs:98:13:98:16 | [post] this access : D [field b, field c] : C | | A.cs:98:30:98:43 | call to method Source : B | A.cs:98:22:98:43 | ... ? ... : ... : B | +| A.cs:98:30:98:43 | call to method Source : B | A.cs:98:22:98:43 | ... ? ... : ... : B | +| A.cs:104:17:104:30 | call to method Source : B | A.cs:105:23:105:23 | access to local variable b : B | | A.cs:104:17:104:30 | call to method Source : B | A.cs:105:23:105:23 | access to local variable b : B | | A.cs:105:17:105:29 | object creation of type D : D [field b, field c] : C | A.cs:107:14:107:14 | access to local variable d : D [field b, field c] : C | +| A.cs:105:17:105:29 | object creation of type D : D [field b, field c] : C | A.cs:107:14:107:14 | access to local variable d : D [field b, field c] : C | +| A.cs:105:17:105:29 | object creation of type D : D [field b] : B | A.cs:106:14:106:14 | access to local variable d : D [field b] : B | | A.cs:105:17:105:29 | object creation of type D : D [field b] : B | A.cs:106:14:106:14 | access to local variable d : D [field b] : B | | A.cs:105:23:105:23 | [post] access to local variable b : B [field c] : C | A.cs:108:14:108:14 | access to local variable b : B [field c] : C | +| A.cs:105:23:105:23 | [post] access to local variable b : B [field c] : C | A.cs:108:14:108:14 | access to local variable b : B [field c] : C | +| A.cs:105:23:105:23 | access to local variable b : B | A.cs:95:20:95:20 | b : B | | A.cs:105:23:105:23 | access to local variable b : B | A.cs:95:20:95:20 | b : B | | A.cs:105:23:105:23 | access to local variable b : B | A.cs:105:17:105:29 | object creation of type D : D [field b] : B | +| A.cs:105:23:105:23 | access to local variable b : B | A.cs:105:17:105:29 | object creation of type D : D [field b] : B | +| A.cs:106:14:106:14 | access to local variable d : D [field b] : B | A.cs:106:14:106:16 | access to field b | | A.cs:106:14:106:14 | access to local variable d : D [field b] : B | A.cs:106:14:106:16 | access to field b | | A.cs:107:14:107:14 | access to local variable d : D [field b, field c] : C | A.cs:107:14:107:16 | access to field b : B [field c] : C | +| A.cs:107:14:107:14 | access to local variable d : D [field b, field c] : C | A.cs:107:14:107:16 | access to field b : B [field c] : C | +| A.cs:107:14:107:16 | access to field b : B [field c] : C | A.cs:107:14:107:18 | access to field c | | A.cs:107:14:107:16 | access to field b : B [field c] : C | A.cs:107:14:107:18 | access to field c | | A.cs:108:14:108:14 | access to local variable b : B [field c] : C | A.cs:108:14:108:16 | access to field c | +| A.cs:108:14:108:14 | access to local variable b : B [field c] : C | A.cs:108:14:108:16 | access to field c | +| A.cs:113:17:113:29 | call to method Source : B | A.cs:114:29:114:29 | access to local variable b : B | | A.cs:113:17:113:29 | call to method Source : B | A.cs:114:29:114:29 | access to local variable b : B | | A.cs:114:18:114:54 | object creation of type MyList : MyList [field head] : B | A.cs:115:35:115:36 | access to local variable l1 : MyList [field head] : B | +| A.cs:114:18:114:54 | object creation of type MyList : MyList [field head] : B | A.cs:115:35:115:36 | access to local variable l1 : MyList [field head] : B | +| A.cs:114:29:114:29 | access to local variable b : B | A.cs:114:18:114:54 | object creation of type MyList : MyList [field head] : B | | A.cs:114:29:114:29 | access to local variable b : B | A.cs:114:18:114:54 | object creation of type MyList : MyList [field head] : B | | A.cs:114:29:114:29 | access to local variable b : B | A.cs:157:25:157:28 | head : B | +| A.cs:114:29:114:29 | access to local variable b : B | A.cs:157:25:157:28 | head : B | +| A.cs:115:18:115:37 | object creation of type MyList : MyList [field next, field head] : B | A.cs:116:35:116:36 | access to local variable l2 : MyList [field next, field head] : B | | A.cs:115:18:115:37 | object creation of type MyList : MyList [field next, field head] : B | A.cs:116:35:116:36 | access to local variable l2 : MyList [field next, field head] : B | | A.cs:115:35:115:36 | access to local variable l1 : MyList [field head] : B | A.cs:115:18:115:37 | object creation of type MyList : MyList [field next, field head] : B | +| A.cs:115:35:115:36 | access to local variable l1 : MyList [field head] : B | A.cs:115:18:115:37 | object creation of type MyList : MyList [field next, field head] : B | +| A.cs:115:35:115:36 | access to local variable l1 : MyList [field head] : B | A.cs:157:38:157:41 | next : MyList [field head] : B | | A.cs:115:35:115:36 | access to local variable l1 : MyList [field head] : B | A.cs:157:38:157:41 | next : MyList [field head] : B | | A.cs:116:18:116:37 | object creation of type MyList : MyList [field next, field next, field head] : B | A.cs:119:14:119:15 | access to local variable l3 : MyList [field next, field next, field head] : B | +| A.cs:116:18:116:37 | object creation of type MyList : MyList [field next, field next, field head] : B | A.cs:119:14:119:15 | access to local variable l3 : MyList [field next, field next, field head] : B | +| A.cs:116:18:116:37 | object creation of type MyList : MyList [field next, field next, field head] : B | A.cs:121:41:121:41 | access to local variable l : MyList [field next, field next, field head] : B | | A.cs:116:18:116:37 | object creation of type MyList : MyList [field next, field next, field head] : B | A.cs:121:41:121:41 | access to local variable l : MyList [field next, field next, field head] : B | | A.cs:116:35:116:36 | access to local variable l2 : MyList [field next, field head] : B | A.cs:116:18:116:37 | object creation of type MyList : MyList [field next, field next, field head] : B | +| A.cs:116:35:116:36 | access to local variable l2 : MyList [field next, field head] : B | A.cs:116:18:116:37 | object creation of type MyList : MyList [field next, field next, field head] : B | +| A.cs:116:35:116:36 | access to local variable l2 : MyList [field next, field head] : B | A.cs:157:38:157:41 | next : MyList [field next, field head] : B | | A.cs:116:35:116:36 | access to local variable l2 : MyList [field next, field head] : B | A.cs:157:38:157:41 | next : MyList [field next, field head] : B | | A.cs:119:14:119:15 | access to local variable l3 : MyList [field next, field next, field head] : B | A.cs:119:14:119:20 | access to field next : MyList [field next, field head] : B | +| A.cs:119:14:119:15 | access to local variable l3 : MyList [field next, field next, field head] : B | A.cs:119:14:119:20 | access to field next : MyList [field next, field head] : B | +| A.cs:119:14:119:20 | access to field next : MyList [field next, field head] : B | A.cs:119:14:119:25 | access to field next : MyList [field head] : B | | A.cs:119:14:119:20 | access to field next : MyList [field next, field head] : B | A.cs:119:14:119:25 | access to field next : MyList [field head] : B | | A.cs:119:14:119:25 | access to field next : MyList [field head] : B | A.cs:119:14:119:30 | access to field head | +| A.cs:119:14:119:25 | access to field next : MyList [field head] : B | A.cs:119:14:119:30 | access to field head | +| A.cs:121:41:121:41 | access to local variable l : MyList [field next, field head] : B | A.cs:121:41:121:46 | access to field next : MyList [field head] : B | | A.cs:121:41:121:41 | access to local variable l : MyList [field next, field head] : B | A.cs:121:41:121:46 | access to field next : MyList [field head] : B | | A.cs:121:41:121:41 | access to local variable l : MyList [field next, field next, field head] : B | A.cs:121:41:121:46 | access to field next : MyList [field next, field head] : B | +| A.cs:121:41:121:41 | access to local variable l : MyList [field next, field next, field head] : B | A.cs:121:41:121:46 | access to field next : MyList [field next, field head] : B | +| A.cs:121:41:121:46 | access to field next : MyList [field head] : B | A.cs:123:18:123:18 | access to local variable l : MyList [field head] : B | | A.cs:121:41:121:46 | access to field next : MyList [field head] : B | A.cs:123:18:123:18 | access to local variable l : MyList [field head] : B | | A.cs:121:41:121:46 | access to field next : MyList [field next, field head] : B | A.cs:121:41:121:41 | access to local variable l : MyList [field next, field head] : B | +| A.cs:121:41:121:46 | access to field next : MyList [field next, field head] : B | A.cs:121:41:121:41 | access to local variable l : MyList [field next, field head] : B | +| A.cs:123:18:123:18 | access to local variable l : MyList [field head] : B | A.cs:123:18:123:23 | access to field head | | A.cs:123:18:123:18 | access to local variable l : MyList [field head] : B | A.cs:123:18:123:23 | access to field head | | A.cs:141:20:141:20 | c : C | A.cs:143:22:143:22 | access to parameter c : C | +| A.cs:141:20:141:20 | c : C | A.cs:143:22:143:22 | access to parameter c : C | +| A.cs:143:22:143:22 | access to parameter c : C | A.cs:143:13:143:16 | [post] this access : B [field c] : C | | A.cs:143:22:143:22 | access to parameter c : C | A.cs:143:13:143:16 | [post] this access : B [field c] : C | | A.cs:145:27:145:27 | c : C | A.cs:145:41:145:41 | access to parameter c : C | +| A.cs:145:27:145:27 | c : C | A.cs:145:41:145:41 | access to parameter c : C | +| A.cs:145:27:145:27 | c : C1 | A.cs:145:41:145:41 | access to parameter c : C1 | | A.cs:145:27:145:27 | c : C1 | A.cs:145:41:145:41 | access to parameter c : C1 | | A.cs:145:27:145:27 | c : C2 | A.cs:145:41:145:41 | access to parameter c : C2 | +| A.cs:145:27:145:27 | c : C2 | A.cs:145:41:145:41 | access to parameter c : C2 | +| A.cs:145:41:145:41 | access to parameter c : C | A.cs:145:32:145:35 | [post] this access : B [field c] : C | | A.cs:145:41:145:41 | access to parameter c : C | A.cs:145:32:145:35 | [post] this access : B [field c] : C | | A.cs:145:41:145:41 | access to parameter c : C1 | A.cs:145:32:145:35 | [post] this access : B [field c] : C1 | +| A.cs:145:41:145:41 | access to parameter c : C1 | A.cs:145:32:145:35 | [post] this access : B [field c] : C1 | +| A.cs:145:41:145:41 | access to parameter c : C2 | A.cs:145:32:145:35 | [post] this access : B [field c] : C2 | | A.cs:145:41:145:41 | access to parameter c : C2 | A.cs:145:32:145:35 | [post] this access : B [field c] : C2 | | A.cs:146:18:146:20 | this : B [field c] : C | A.cs:146:33:146:36 | this access : B [field c] : C | +| A.cs:146:18:146:20 | this : B [field c] : C | A.cs:146:33:146:36 | this access : B [field c] : C | +| A.cs:146:18:146:20 | this : B [field c] : C1 | A.cs:146:33:146:36 | this access : B [field c] : C1 | | A.cs:146:18:146:20 | this : B [field c] : C1 | A.cs:146:33:146:36 | this access : B [field c] : C1 | | A.cs:146:33:146:36 | this access : B [field c] : C | A.cs:146:33:146:38 | access to field c : C | +| A.cs:146:33:146:36 | this access : B [field c] : C | A.cs:146:33:146:38 | access to field c : C | +| A.cs:146:33:146:36 | this access : B [field c] : C1 | A.cs:146:33:146:38 | access to field c : C1 | | A.cs:146:33:146:36 | this access : B [field c] : C1 | A.cs:146:33:146:38 | access to field c : C1 | | A.cs:147:32:147:32 | c : C | A.cs:149:26:149:26 | access to parameter c : C | +| A.cs:147:32:147:32 | c : C | A.cs:149:26:149:26 | access to parameter c : C | +| A.cs:149:26:149:26 | access to parameter c : C | A.cs:141:20:141:20 | c : C | | A.cs:149:26:149:26 | access to parameter c : C | A.cs:141:20:141:20 | c : C | | A.cs:149:26:149:26 | access to parameter c : C | A.cs:149:20:149:27 | object creation of type B : B [field c] : C | +| A.cs:149:26:149:26 | access to parameter c : C | A.cs:149:20:149:27 | object creation of type B : B [field c] : C | +| A.cs:157:25:157:28 | head : B | A.cs:159:25:159:28 | access to parameter head : B | | A.cs:157:25:157:28 | head : B | A.cs:159:25:159:28 | access to parameter head : B | | A.cs:157:38:157:41 | next : MyList [field head] : B | A.cs:160:25:160:28 | access to parameter next : MyList [field head] : B | +| A.cs:157:38:157:41 | next : MyList [field head] : B | A.cs:160:25:160:28 | access to parameter next : MyList [field head] : B | +| A.cs:157:38:157:41 | next : MyList [field next, field head] : B | A.cs:160:25:160:28 | access to parameter next : MyList [field next, field head] : B | | A.cs:157:38:157:41 | next : MyList [field next, field head] : B | A.cs:160:25:160:28 | access to parameter next : MyList [field next, field head] : B | | A.cs:159:25:159:28 | access to parameter head : B | A.cs:159:13:159:16 | [post] this access : MyList [field head] : B | +| A.cs:159:25:159:28 | access to parameter head : B | A.cs:159:13:159:16 | [post] this access : MyList [field head] : B | +| A.cs:160:25:160:28 | access to parameter next : MyList [field head] : B | A.cs:160:13:160:16 | [post] this access : MyList [field next, field head] : B | | A.cs:160:25:160:28 | access to parameter next : MyList [field head] : B | A.cs:160:13:160:16 | [post] this access : MyList [field next, field head] : B | | A.cs:160:25:160:28 | access to parameter next : MyList [field next, field head] : B | A.cs:160:13:160:16 | [post] this access : MyList [field next, field next, field head] : B | +| A.cs:160:25:160:28 | access to parameter next : MyList [field next, field head] : B | A.cs:160:13:160:16 | [post] this access : MyList [field next, field next, field head] : B | +| B.cs:5:17:5:31 | call to method Source : Elem | B.cs:6:27:6:27 | access to local variable e : Elem | | B.cs:5:17:5:31 | call to method Source : Elem | B.cs:6:27:6:27 | access to local variable e : Elem | | B.cs:6:18:6:34 | object creation of type Box1 : Box1 [field elem1] : Elem | B.cs:7:27:7:28 | access to local variable b1 : Box1 [field elem1] : Elem | +| B.cs:6:18:6:34 | object creation of type Box1 : Box1 [field elem1] : Elem | B.cs:7:27:7:28 | access to local variable b1 : Box1 [field elem1] : Elem | +| B.cs:6:27:6:27 | access to local variable e : Elem | B.cs:6:18:6:34 | object creation of type Box1 : Box1 [field elem1] : Elem | | B.cs:6:27:6:27 | access to local variable e : Elem | B.cs:6:18:6:34 | object creation of type Box1 : Box1 [field elem1] : Elem | | B.cs:6:27:6:27 | access to local variable e : Elem | B.cs:29:26:29:27 | e1 : Elem | +| B.cs:6:27:6:27 | access to local variable e : Elem | B.cs:29:26:29:27 | e1 : Elem | +| B.cs:7:18:7:29 | object creation of type Box2 : Box2 [field box1, field elem1] : Elem | B.cs:8:14:8:15 | access to local variable b2 : Box2 [field box1, field elem1] : Elem | | B.cs:7:18:7:29 | object creation of type Box2 : Box2 [field box1, field elem1] : Elem | B.cs:8:14:8:15 | access to local variable b2 : Box2 [field box1, field elem1] : Elem | | B.cs:7:27:7:28 | access to local variable b1 : Box1 [field elem1] : Elem | B.cs:7:18:7:29 | object creation of type Box2 : Box2 [field box1, field elem1] : Elem | +| B.cs:7:27:7:28 | access to local variable b1 : Box1 [field elem1] : Elem | B.cs:7:18:7:29 | object creation of type Box2 : Box2 [field box1, field elem1] : Elem | +| B.cs:7:27:7:28 | access to local variable b1 : Box1 [field elem1] : Elem | B.cs:39:26:39:27 | b1 : Box1 [field elem1] : Elem | | B.cs:7:27:7:28 | access to local variable b1 : Box1 [field elem1] : Elem | B.cs:39:26:39:27 | b1 : Box1 [field elem1] : Elem | | B.cs:8:14:8:15 | access to local variable b2 : Box2 [field box1, field elem1] : Elem | B.cs:8:14:8:20 | access to field box1 : Box1 [field elem1] : Elem | +| B.cs:8:14:8:15 | access to local variable b2 : Box2 [field box1, field elem1] : Elem | B.cs:8:14:8:20 | access to field box1 : Box1 [field elem1] : Elem | +| B.cs:8:14:8:20 | access to field box1 : Box1 [field elem1] : Elem | B.cs:8:14:8:26 | access to field elem1 | | B.cs:8:14:8:20 | access to field box1 : Box1 [field elem1] : Elem | B.cs:8:14:8:26 | access to field elem1 | | B.cs:14:17:14:31 | call to method Source : Elem | B.cs:15:33:15:33 | access to local variable e : Elem | +| B.cs:14:17:14:31 | call to method Source : Elem | B.cs:15:33:15:33 | access to local variable e : Elem | +| B.cs:15:18:15:34 | object creation of type Box1 : Box1 [field elem2] : Elem | B.cs:16:27:16:28 | access to local variable b1 : Box1 [field elem2] : Elem | | B.cs:15:18:15:34 | object creation of type Box1 : Box1 [field elem2] : Elem | B.cs:16:27:16:28 | access to local variable b1 : Box1 [field elem2] : Elem | | B.cs:15:33:15:33 | access to local variable e : Elem | B.cs:15:18:15:34 | object creation of type Box1 : Box1 [field elem2] : Elem | +| B.cs:15:33:15:33 | access to local variable e : Elem | B.cs:15:18:15:34 | object creation of type Box1 : Box1 [field elem2] : Elem | +| B.cs:15:33:15:33 | access to local variable e : Elem | B.cs:29:35:29:36 | e2 : Elem | | B.cs:15:33:15:33 | access to local variable e : Elem | B.cs:29:35:29:36 | e2 : Elem | | B.cs:16:18:16:29 | object creation of type Box2 : Box2 [field box1, field elem2] : Elem | B.cs:18:14:18:15 | access to local variable b2 : Box2 [field box1, field elem2] : Elem | +| B.cs:16:18:16:29 | object creation of type Box2 : Box2 [field box1, field elem2] : Elem | B.cs:18:14:18:15 | access to local variable b2 : Box2 [field box1, field elem2] : Elem | +| B.cs:16:27:16:28 | access to local variable b1 : Box1 [field elem2] : Elem | B.cs:16:18:16:29 | object creation of type Box2 : Box2 [field box1, field elem2] : Elem | | B.cs:16:27:16:28 | access to local variable b1 : Box1 [field elem2] : Elem | B.cs:16:18:16:29 | object creation of type Box2 : Box2 [field box1, field elem2] : Elem | | B.cs:16:27:16:28 | access to local variable b1 : Box1 [field elem2] : Elem | B.cs:39:26:39:27 | b1 : Box1 [field elem2] : Elem | +| B.cs:16:27:16:28 | access to local variable b1 : Box1 [field elem2] : Elem | B.cs:39:26:39:27 | b1 : Box1 [field elem2] : Elem | +| B.cs:18:14:18:15 | access to local variable b2 : Box2 [field box1, field elem2] : Elem | B.cs:18:14:18:20 | access to field box1 : Box1 [field elem2] : Elem | | B.cs:18:14:18:15 | access to local variable b2 : Box2 [field box1, field elem2] : Elem | B.cs:18:14:18:20 | access to field box1 : Box1 [field elem2] : Elem | | B.cs:18:14:18:20 | access to field box1 : Box1 [field elem2] : Elem | B.cs:18:14:18:26 | access to field elem2 | +| B.cs:18:14:18:20 | access to field box1 : Box1 [field elem2] : Elem | B.cs:18:14:18:26 | access to field elem2 | +| B.cs:29:26:29:27 | e1 : Elem | B.cs:31:26:31:27 | access to parameter e1 : Elem | | B.cs:29:26:29:27 | e1 : Elem | B.cs:31:26:31:27 | access to parameter e1 : Elem | | B.cs:29:35:29:36 | e2 : Elem | B.cs:32:26:32:27 | access to parameter e2 : Elem | +| B.cs:29:35:29:36 | e2 : Elem | B.cs:32:26:32:27 | access to parameter e2 : Elem | +| B.cs:31:26:31:27 | access to parameter e1 : Elem | B.cs:31:13:31:16 | [post] this access : Box1 [field elem1] : Elem | | B.cs:31:26:31:27 | access to parameter e1 : Elem | B.cs:31:13:31:16 | [post] this access : Box1 [field elem1] : Elem | | B.cs:32:26:32:27 | access to parameter e2 : Elem | B.cs:32:13:32:16 | [post] this access : Box1 [field elem2] : Elem | +| B.cs:32:26:32:27 | access to parameter e2 : Elem | B.cs:32:13:32:16 | [post] this access : Box1 [field elem2] : Elem | +| B.cs:39:26:39:27 | b1 : Box1 [field elem1] : Elem | B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem1] : Elem | | B.cs:39:26:39:27 | b1 : Box1 [field elem1] : Elem | B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem1] : Elem | | B.cs:39:26:39:27 | b1 : Box1 [field elem2] : Elem | B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem2] : Elem | +| B.cs:39:26:39:27 | b1 : Box1 [field elem2] : Elem | B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem2] : Elem | +| B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem1] : Elem | B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem1] : Elem | | B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem1] : Elem | B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem1] : Elem | | B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem2] : Elem | B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem2] : Elem | +| B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem2] : Elem | B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem2] : Elem | +| C.cs:3:18:3:19 | [post] this access : C [field s1] : Elem | C.cs:12:15:12:21 | object creation of type C : C [field s1] : Elem | | C.cs:3:18:3:19 | [post] this access : C [field s1] : Elem | C.cs:12:15:12:21 | object creation of type C : C [field s1] : Elem | | C.cs:3:23:3:37 | call to method Source : Elem | C.cs:3:18:3:19 | [post] this access : C [field s1] : Elem | +| C.cs:3:23:3:37 | call to method Source : Elem | C.cs:3:18:3:19 | [post] this access : C [field s1] : Elem | +| C.cs:4:27:4:28 | [post] this access : C [field s2] : Elem | C.cs:12:15:12:21 | object creation of type C : C [field s2] : Elem | | C.cs:4:27:4:28 | [post] this access : C [field s2] : Elem | C.cs:12:15:12:21 | object creation of type C : C [field s2] : Elem | | C.cs:4:32:4:46 | call to method Source : Elem | C.cs:4:27:4:28 | [post] this access : C [field s2] : Elem | +| C.cs:4:32:4:46 | call to method Source : Elem | C.cs:4:27:4:28 | [post] this access : C [field s2] : Elem | +| C.cs:6:30:6:44 | call to method Source : Elem | C.cs:26:14:26:15 | access to field s4 | | C.cs:6:30:6:44 | call to method Source : Elem | C.cs:26:14:26:15 | access to field s4 | | C.cs:7:18:7:19 | [post] this access : C [property s5] : Elem | C.cs:12:15:12:21 | object creation of type C : C [property s5] : Elem | +| C.cs:7:18:7:19 | [post] this access : C [property s5] : Elem | C.cs:12:15:12:21 | object creation of type C : C [property s5] : Elem | +| C.cs:7:37:7:51 | call to method Source : Elem | C.cs:7:18:7:19 | [post] this access : C [property s5] : Elem | | C.cs:7:37:7:51 | call to method Source : Elem | C.cs:7:18:7:19 | [post] this access : C [property s5] : Elem | | C.cs:8:30:8:44 | call to method Source : Elem | C.cs:28:14:28:15 | access to property s6 | +| C.cs:8:30:8:44 | call to method Source : Elem | C.cs:28:14:28:15 | access to property s6 | +| C.cs:12:15:12:21 | object creation of type C : C [field s1] : Elem | C.cs:13:9:13:9 | access to local variable c : C [field s1] : Elem | | C.cs:12:15:12:21 | object creation of type C : C [field s1] : Elem | C.cs:13:9:13:9 | access to local variable c : C [field s1] : Elem | | C.cs:12:15:12:21 | object creation of type C : C [field s2] : Elem | C.cs:13:9:13:9 | access to local variable c : C [field s2] : Elem | +| C.cs:12:15:12:21 | object creation of type C : C [field s2] : Elem | C.cs:13:9:13:9 | access to local variable c : C [field s2] : Elem | +| C.cs:12:15:12:21 | object creation of type C : C [field s3] : Elem | C.cs:13:9:13:9 | access to local variable c : C [field s3] : Elem | | C.cs:12:15:12:21 | object creation of type C : C [field s3] : Elem | C.cs:13:9:13:9 | access to local variable c : C [field s3] : Elem | | C.cs:12:15:12:21 | object creation of type C : C [property s5] : Elem | C.cs:13:9:13:9 | access to local variable c : C [property s5] : Elem | +| C.cs:12:15:12:21 | object creation of type C : C [property s5] : Elem | C.cs:13:9:13:9 | access to local variable c : C [property s5] : Elem | +| C.cs:13:9:13:9 | access to local variable c : C [field s1] : Elem | C.cs:21:17:21:18 | this : C [field s1] : Elem | | C.cs:13:9:13:9 | access to local variable c : C [field s1] : Elem | C.cs:21:17:21:18 | this : C [field s1] : Elem | | C.cs:13:9:13:9 | access to local variable c : C [field s2] : Elem | C.cs:21:17:21:18 | this : C [field s2] : Elem | +| C.cs:13:9:13:9 | access to local variable c : C [field s2] : Elem | C.cs:21:17:21:18 | this : C [field s2] : Elem | +| C.cs:13:9:13:9 | access to local variable c : C [field s3] : Elem | C.cs:21:17:21:18 | this : C [field s3] : Elem | | C.cs:13:9:13:9 | access to local variable c : C [field s3] : Elem | C.cs:21:17:21:18 | this : C [field s3] : Elem | | C.cs:13:9:13:9 | access to local variable c : C [property s5] : Elem | C.cs:21:17:21:18 | this : C [property s5] : Elem | +| C.cs:13:9:13:9 | access to local variable c : C [property s5] : Elem | C.cs:21:17:21:18 | this : C [property s5] : Elem | +| C.cs:18:9:18:12 | [post] this access : C [field s3] : Elem | C.cs:12:15:12:21 | object creation of type C : C [field s3] : Elem | | C.cs:18:9:18:12 | [post] this access : C [field s3] : Elem | C.cs:12:15:12:21 | object creation of type C : C [field s3] : Elem | | C.cs:18:19:18:33 | call to method Source : Elem | C.cs:18:9:18:12 | [post] this access : C [field s3] : Elem | +| C.cs:18:19:18:33 | call to method Source : Elem | C.cs:18:9:18:12 | [post] this access : C [field s3] : Elem | +| C.cs:21:17:21:18 | this : C [field s1] : Elem | C.cs:23:14:23:15 | this access : C [field s1] : Elem | | C.cs:21:17:21:18 | this : C [field s1] : Elem | C.cs:23:14:23:15 | this access : C [field s1] : Elem | | C.cs:21:17:21:18 | this : C [field s2] : Elem | C.cs:24:14:24:15 | this access : C [field s2] : Elem | +| C.cs:21:17:21:18 | this : C [field s2] : Elem | C.cs:24:14:24:15 | this access : C [field s2] : Elem | +| C.cs:21:17:21:18 | this : C [field s3] : Elem | C.cs:25:14:25:15 | this access : C [field s3] : Elem | | C.cs:21:17:21:18 | this : C [field s3] : Elem | C.cs:25:14:25:15 | this access : C [field s3] : Elem | | C.cs:21:17:21:18 | this : C [property s5] : Elem | C.cs:27:14:27:15 | this access : C [property s5] : Elem | +| C.cs:21:17:21:18 | this : C [property s5] : Elem | C.cs:27:14:27:15 | this access : C [property s5] : Elem | +| C.cs:23:14:23:15 | this access : C [field s1] : Elem | C.cs:23:14:23:15 | access to field s1 | | C.cs:23:14:23:15 | this access : C [field s1] : Elem | C.cs:23:14:23:15 | access to field s1 | | C.cs:24:14:24:15 | this access : C [field s2] : Elem | C.cs:24:14:24:15 | access to field s2 | +| C.cs:24:14:24:15 | this access : C [field s2] : Elem | C.cs:24:14:24:15 | access to field s2 | +| C.cs:25:14:25:15 | this access : C [field s3] : Elem | C.cs:25:14:25:15 | access to field s3 | | C.cs:25:14:25:15 | this access : C [field s3] : Elem | C.cs:25:14:25:15 | access to field s3 | | C.cs:27:14:27:15 | this access : C [property s5] : Elem | C.cs:27:14:27:15 | access to property s5 | +| C.cs:27:14:27:15 | this access : C [property s5] : Elem | C.cs:27:14:27:15 | access to property s5 | +| C_ctor.cs:3:18:3:19 | [post] this access : C_no_ctor [field s1] : Elem | C_ctor.cs:7:23:7:37 | object creation of type C_no_ctor : C_no_ctor [field s1] : Elem | | C_ctor.cs:3:18:3:19 | [post] this access : C_no_ctor [field s1] : Elem | C_ctor.cs:7:23:7:37 | object creation of type C_no_ctor : C_no_ctor [field s1] : Elem | | C_ctor.cs:3:23:3:42 | call to method Source : Elem | C_ctor.cs:3:18:3:19 | [post] this access : C_no_ctor [field s1] : Elem | +| C_ctor.cs:3:23:3:42 | call to method Source : Elem | C_ctor.cs:3:18:3:19 | [post] this access : C_no_ctor [field s1] : Elem | +| C_ctor.cs:7:23:7:37 | object creation of type C_no_ctor : C_no_ctor [field s1] : Elem | C_ctor.cs:8:9:8:9 | access to local variable c : C_no_ctor [field s1] : Elem | | C_ctor.cs:7:23:7:37 | object creation of type C_no_ctor : C_no_ctor [field s1] : Elem | C_ctor.cs:8:9:8:9 | access to local variable c : C_no_ctor [field s1] : Elem | | C_ctor.cs:8:9:8:9 | access to local variable c : C_no_ctor [field s1] : Elem | C_ctor.cs:11:17:11:18 | this : C_no_ctor [field s1] : Elem | +| C_ctor.cs:8:9:8:9 | access to local variable c : C_no_ctor [field s1] : Elem | C_ctor.cs:11:17:11:18 | this : C_no_ctor [field s1] : Elem | +| C_ctor.cs:11:17:11:18 | this : C_no_ctor [field s1] : Elem | C_ctor.cs:13:19:13:20 | this access : C_no_ctor [field s1] : Elem | | C_ctor.cs:11:17:11:18 | this : C_no_ctor [field s1] : Elem | C_ctor.cs:13:19:13:20 | this access : C_no_ctor [field s1] : Elem | | C_ctor.cs:13:19:13:20 | this access : C_no_ctor [field s1] : Elem | C_ctor.cs:13:19:13:20 | access to field s1 | +| C_ctor.cs:13:19:13:20 | this access : C_no_ctor [field s1] : Elem | C_ctor.cs:13:19:13:20 | access to field s1 | +| C_ctor.cs:19:18:19:19 | [post] this access : C_with_ctor [field s1] : Elem | C_ctor.cs:23:25:23:41 | object creation of type C_with_ctor : C_with_ctor [field s1] : Elem | | C_ctor.cs:19:18:19:19 | [post] this access : C_with_ctor [field s1] : Elem | C_ctor.cs:23:25:23:41 | object creation of type C_with_ctor : C_with_ctor [field s1] : Elem | | C_ctor.cs:19:23:19:42 | call to method Source : Elem | C_ctor.cs:19:18:19:19 | [post] this access : C_with_ctor [field s1] : Elem | +| C_ctor.cs:19:23:19:42 | call to method Source : Elem | C_ctor.cs:19:18:19:19 | [post] this access : C_with_ctor [field s1] : Elem | +| C_ctor.cs:23:25:23:41 | object creation of type C_with_ctor : C_with_ctor [field s1] : Elem | C_ctor.cs:24:9:24:9 | access to local variable c : C_with_ctor [field s1] : Elem | | C_ctor.cs:23:25:23:41 | object creation of type C_with_ctor : C_with_ctor [field s1] : Elem | C_ctor.cs:24:9:24:9 | access to local variable c : C_with_ctor [field s1] : Elem | | C_ctor.cs:24:9:24:9 | access to local variable c : C_with_ctor [field s1] : Elem | C_ctor.cs:29:17:29:18 | this : C_with_ctor [field s1] : Elem | +| C_ctor.cs:24:9:24:9 | access to local variable c : C_with_ctor [field s1] : Elem | C_ctor.cs:29:17:29:18 | this : C_with_ctor [field s1] : Elem | +| C_ctor.cs:29:17:29:18 | this : C_with_ctor [field s1] : Elem | C_ctor.cs:31:19:31:20 | this access : C_with_ctor [field s1] : Elem | | C_ctor.cs:29:17:29:18 | this : C_with_ctor [field s1] : Elem | C_ctor.cs:31:19:31:20 | this access : C_with_ctor [field s1] : Elem | | C_ctor.cs:31:19:31:20 | this access : C_with_ctor [field s1] : Elem | C_ctor.cs:31:19:31:20 | access to field s1 | +| C_ctor.cs:31:19:31:20 | this access : C_with_ctor [field s1] : Elem | C_ctor.cs:31:19:31:20 | access to field s1 | +| D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | D.cs:8:22:8:25 | this access : D [field trivialPropField] : Object | | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | D.cs:8:22:8:25 | this access : D [field trivialPropField] : Object | | D.cs:8:22:8:25 | this access : D [field trivialPropField] : Object | D.cs:8:22:8:42 | access to field trivialPropField : Object | +| D.cs:8:22:8:25 | this access : D [field trivialPropField] : Object | D.cs:8:22:8:42 | access to field trivialPropField : Object | +| D.cs:9:9:9:11 | value : Object | D.cs:9:39:9:43 | access to parameter value : Object | | D.cs:9:9:9:11 | value : Object | D.cs:9:39:9:43 | access to parameter value : Object | | D.cs:9:39:9:43 | access to parameter value : Object | D.cs:9:15:9:18 | [post] this access : D [field trivialPropField] : Object | +| D.cs:9:39:9:43 | access to parameter value : Object | D.cs:9:15:9:18 | [post] this access : D [field trivialPropField] : Object | +| D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | D.cs:14:22:14:25 | this access : D [field trivialPropField] : Object | | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | D.cs:14:22:14:25 | this access : D [field trivialPropField] : Object | | D.cs:14:22:14:25 | this access : D [field trivialPropField] : Object | D.cs:14:22:14:42 | access to field trivialPropField : Object | +| D.cs:14:22:14:25 | this access : D [field trivialPropField] : Object | D.cs:14:22:14:42 | access to field trivialPropField : Object | +| D.cs:15:9:15:11 | value : Object | D.cs:15:34:15:38 | access to parameter value : Object | | D.cs:15:9:15:11 | value : Object | D.cs:15:34:15:38 | access to parameter value : Object | | D.cs:15:34:15:38 | access to parameter value : Object | D.cs:9:9:9:11 | value : Object | +| D.cs:15:34:15:38 | access to parameter value : Object | D.cs:9:9:9:11 | value : Object | +| D.cs:15:34:15:38 | access to parameter value : Object | D.cs:15:15:15:18 | [post] this access : D [field trivialPropField] : Object | | D.cs:15:34:15:38 | access to parameter value : Object | D.cs:15:15:15:18 | [post] this access : D [field trivialPropField] : Object | | D.cs:18:28:18:29 | o1 : Object | D.cs:21:24:21:25 | access to parameter o1 : Object | +| D.cs:18:28:18:29 | o1 : Object | D.cs:21:24:21:25 | access to parameter o1 : Object | +| D.cs:18:39:18:40 | o2 : Object | D.cs:22:27:22:28 | access to parameter o2 : Object | | D.cs:18:39:18:40 | o2 : Object | D.cs:22:27:22:28 | access to parameter o2 : Object | | D.cs:18:50:18:51 | o3 : Object | D.cs:23:27:23:28 | access to parameter o3 : Object | +| D.cs:18:50:18:51 | o3 : Object | D.cs:23:27:23:28 | access to parameter o3 : Object | +| D.cs:21:9:21:11 | [post] access to local variable ret : D [property AutoProp] : Object | D.cs:24:16:24:18 | access to local variable ret : D [property AutoProp] : Object | | D.cs:21:9:21:11 | [post] access to local variable ret : D [property AutoProp] : Object | D.cs:24:16:24:18 | access to local variable ret : D [property AutoProp] : Object | | D.cs:21:24:21:25 | access to parameter o1 : Object | D.cs:21:9:21:11 | [post] access to local variable ret : D [property AutoProp] : Object | +| D.cs:21:24:21:25 | access to parameter o1 : Object | D.cs:21:9:21:11 | [post] access to local variable ret : D [property AutoProp] : Object | +| D.cs:22:9:22:11 | [post] access to local variable ret : D [field trivialPropField] : Object | D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | | D.cs:22:9:22:11 | [post] access to local variable ret : D [field trivialPropField] : Object | D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | | D.cs:22:27:22:28 | access to parameter o2 : Object | D.cs:9:9:9:11 | value : Object | +| D.cs:22:27:22:28 | access to parameter o2 : Object | D.cs:9:9:9:11 | value : Object | +| D.cs:22:27:22:28 | access to parameter o2 : Object | D.cs:22:9:22:11 | [post] access to local variable ret : D [field trivialPropField] : Object | | D.cs:22:27:22:28 | access to parameter o2 : Object | D.cs:22:9:22:11 | [post] access to local variable ret : D [field trivialPropField] : Object | | D.cs:23:9:23:11 | [post] access to local variable ret : D [field trivialPropField] : Object | D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | +| D.cs:23:9:23:11 | [post] access to local variable ret : D [field trivialPropField] : Object | D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | +| D.cs:23:27:23:28 | access to parameter o3 : Object | D.cs:15:9:15:11 | value : Object | | D.cs:23:27:23:28 | access to parameter o3 : Object | D.cs:15:9:15:11 | value : Object | | D.cs:23:27:23:28 | access to parameter o3 : Object | D.cs:23:9:23:11 | [post] access to local variable ret : D [field trivialPropField] : Object | +| D.cs:23:27:23:28 | access to parameter o3 : Object | D.cs:23:9:23:11 | [post] access to local variable ret : D [field trivialPropField] : Object | +| D.cs:29:17:29:33 | call to method Source : Object | D.cs:31:24:31:24 | access to local variable o : Object | | D.cs:29:17:29:33 | call to method Source : Object | D.cs:31:24:31:24 | access to local variable o : Object | | D.cs:31:17:31:37 | call to method Create : D [property AutoProp] : Object | D.cs:32:14:32:14 | access to local variable d : D [property AutoProp] : Object | +| D.cs:31:17:31:37 | call to method Create : D [property AutoProp] : Object | D.cs:32:14:32:14 | access to local variable d : D [property AutoProp] : Object | +| D.cs:31:24:31:24 | access to local variable o : Object | D.cs:18:28:18:29 | o1 : Object | | D.cs:31:24:31:24 | access to local variable o : Object | D.cs:18:28:18:29 | o1 : Object | | D.cs:31:24:31:24 | access to local variable o : Object | D.cs:31:17:31:37 | call to method Create : D [property AutoProp] : Object | +| D.cs:31:24:31:24 | access to local variable o : Object | D.cs:31:17:31:37 | call to method Create : D [property AutoProp] : Object | +| D.cs:32:14:32:14 | access to local variable d : D [property AutoProp] : Object | D.cs:32:14:32:23 | access to property AutoProp | | D.cs:32:14:32:14 | access to local variable d : D [property AutoProp] : Object | D.cs:32:14:32:23 | access to property AutoProp | | D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | D.cs:39:14:39:14 | access to local variable d : D [field trivialPropField] : Object | +| D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | D.cs:39:14:39:14 | access to local variable d : D [field trivialPropField] : Object | +| D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | D.cs:40:14:40:14 | access to local variable d : D [field trivialPropField] : Object | | D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | D.cs:40:14:40:14 | access to local variable d : D [field trivialPropField] : Object | | D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | D.cs:41:14:41:14 | access to local variable d : D [field trivialPropField] : Object | +| D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | D.cs:41:14:41:14 | access to local variable d : D [field trivialPropField] : Object | +| D.cs:37:26:37:42 | call to method Source : Object | D.cs:18:39:18:40 | o2 : Object | | D.cs:37:26:37:42 | call to method Source : Object | D.cs:18:39:18:40 | o2 : Object | | D.cs:37:26:37:42 | call to method Source : Object | D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | +| D.cs:37:26:37:42 | call to method Source : Object | D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | +| D.cs:39:14:39:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | | D.cs:39:14:39:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | | D.cs:39:14:39:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:39:14:39:26 | access to property TrivialProp | +| D.cs:39:14:39:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:39:14:39:26 | access to property TrivialProp | +| D.cs:40:14:40:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:40:14:40:31 | access to field trivialPropField | | D.cs:40:14:40:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:40:14:40:31 | access to field trivialPropField | | D.cs:41:14:41:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | +| D.cs:41:14:41:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | +| D.cs:41:14:41:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:41:14:41:26 | access to property ComplexProp | | D.cs:41:14:41:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:41:14:41:26 | access to property ComplexProp | | D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | +| D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | +| D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | D.cs:46:14:46:14 | access to local variable d : D [field trivialPropField] : Object | | D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | D.cs:46:14:46:14 | access to local variable d : D [field trivialPropField] : Object | | D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | +| D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | +| D.cs:43:32:43:48 | call to method Source : Object | D.cs:18:50:18:51 | o3 : Object | | D.cs:43:32:43:48 | call to method Source : Object | D.cs:18:50:18:51 | o3 : Object | | D.cs:43:32:43:48 | call to method Source : Object | D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | +| D.cs:43:32:43:48 | call to method Source : Object | D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | +| D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | | D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | | D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:45:14:45:26 | access to property TrivialProp | +| D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:45:14:45:26 | access to property TrivialProp | +| D.cs:46:14:46:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:46:14:46:31 | access to field trivialPropField | | D.cs:46:14:46:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:46:14:46:31 | access to field trivialPropField | | D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | +| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | +| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:47:14:47:26 | access to property ComplexProp | | D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:47:14:47:26 | access to property ComplexProp | | E.cs:8:29:8:29 | o : Object | E.cs:11:21:11:21 | access to parameter o : Object | +| E.cs:8:29:8:29 | o : Object | E.cs:11:21:11:21 | access to parameter o : Object | +| E.cs:11:9:11:11 | [post] access to local variable ret : S [field Field] : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | | E.cs:11:9:11:11 | [post] access to local variable ret : S [field Field] : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | | E.cs:11:21:11:21 | access to parameter o : Object | E.cs:11:9:11:11 | [post] access to local variable ret : S [field Field] : Object | +| E.cs:11:21:11:21 | access to parameter o : Object | E.cs:11:9:11:11 | [post] access to local variable ret : S [field Field] : Object | +| E.cs:22:17:22:33 | call to method Source : Object | E.cs:23:25:23:25 | access to local variable o : Object | | E.cs:22:17:22:33 | call to method Source : Object | E.cs:23:25:23:25 | access to local variable o : Object | | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object | E.cs:24:14:24:14 | access to local variable s : S [field Field] : Object | +| E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object | E.cs:24:14:24:14 | access to local variable s : S [field Field] : Object | +| E.cs:23:25:23:25 | access to local variable o : Object | E.cs:8:29:8:29 | o : Object | | E.cs:23:25:23:25 | access to local variable o : Object | E.cs:8:29:8:29 | o : Object | | E.cs:23:25:23:25 | access to local variable o : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object | +| E.cs:23:25:23:25 | access to local variable o : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object | +| E.cs:24:14:24:14 | access to local variable s : S [field Field] : Object | E.cs:24:14:24:20 | access to field Field | | E.cs:24:14:24:14 | access to local variable s : S [field Field] : Object | E.cs:24:14:24:20 | access to field Field | | F.cs:6:28:6:29 | o1 : Object | F.cs:6:65:6:66 | access to parameter o1 : Object | +| F.cs:6:28:6:29 | o1 : Object | F.cs:6:65:6:66 | access to parameter o1 : Object | +| F.cs:6:39:6:40 | o2 : Object | F.cs:6:78:6:79 | access to parameter o2 : Object | | F.cs:6:39:6:40 | o2 : Object | F.cs:6:78:6:79 | access to parameter o2 : Object | | F.cs:6:54:6:81 | { ..., ... } : F [field Field1] : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field1] : Object | +| F.cs:6:54:6:81 | { ..., ... } : F [field Field1] : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field1] : Object | +| F.cs:6:54:6:81 | { ..., ... } : F [field Field2] : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field2] : Object | | F.cs:6:54:6:81 | { ..., ... } : F [field Field2] : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field2] : Object | | F.cs:6:65:6:66 | access to parameter o1 : Object | F.cs:6:54:6:81 | { ..., ... } : F [field Field1] : Object | +| F.cs:6:65:6:66 | access to parameter o1 : Object | F.cs:6:54:6:81 | { ..., ... } : F [field Field1] : Object | +| F.cs:6:78:6:79 | access to parameter o2 : Object | F.cs:6:54:6:81 | { ..., ... } : F [field Field2] : Object | | F.cs:6:78:6:79 | access to parameter o2 : Object | F.cs:6:54:6:81 | { ..., ... } : F [field Field2] : Object | | F.cs:10:17:10:33 | call to method Source : Object | F.cs:11:24:11:24 | access to local variable o : Object | +| F.cs:10:17:10:33 | call to method Source : Object | F.cs:11:24:11:24 | access to local variable o : Object | +| F.cs:11:17:11:31 | call to method Create : F [field Field1] : Object | F.cs:12:14:12:14 | access to local variable f : F [field Field1] : Object | | F.cs:11:17:11:31 | call to method Create : F [field Field1] : Object | F.cs:12:14:12:14 | access to local variable f : F [field Field1] : Object | | F.cs:11:24:11:24 | access to local variable o : Object | F.cs:6:28:6:29 | o1 : Object | +| F.cs:11:24:11:24 | access to local variable o : Object | F.cs:6:28:6:29 | o1 : Object | +| F.cs:11:24:11:24 | access to local variable o : Object | F.cs:11:17:11:31 | call to method Create : F [field Field1] : Object | | F.cs:11:24:11:24 | access to local variable o : Object | F.cs:11:17:11:31 | call to method Create : F [field Field1] : Object | | F.cs:12:14:12:14 | access to local variable f : F [field Field1] : Object | F.cs:12:14:12:21 | access to field Field1 | +| F.cs:12:14:12:14 | access to local variable f : F [field Field1] : Object | F.cs:12:14:12:21 | access to field Field1 | +| F.cs:15:13:15:43 | call to method Create : F [field Field2] : Object | F.cs:17:14:17:14 | access to local variable f : F [field Field2] : Object | | F.cs:15:13:15:43 | call to method Create : F [field Field2] : Object | F.cs:17:14:17:14 | access to local variable f : F [field Field2] : Object | | F.cs:15:26:15:42 | call to method Source : Object | F.cs:6:39:6:40 | o2 : Object | +| F.cs:15:26:15:42 | call to method Source : Object | F.cs:6:39:6:40 | o2 : Object | +| F.cs:15:26:15:42 | call to method Source : Object | F.cs:15:13:15:43 | call to method Create : F [field Field2] : Object | | F.cs:15:26:15:42 | call to method Source : Object | F.cs:15:13:15:43 | call to method Create : F [field Field2] : Object | | F.cs:17:14:17:14 | access to local variable f : F [field Field2] : Object | F.cs:17:14:17:21 | access to field Field2 | +| F.cs:17:14:17:14 | access to local variable f : F [field Field2] : Object | F.cs:17:14:17:21 | access to field Field2 | +| F.cs:19:21:19:50 | { ..., ... } : F [field Field1] : Object | F.cs:20:14:20:14 | access to local variable f : F [field Field1] : Object | | F.cs:19:21:19:50 | { ..., ... } : F [field Field1] : Object | F.cs:20:14:20:14 | access to local variable f : F [field Field1] : Object | | F.cs:19:32:19:48 | call to method Source : Object | F.cs:19:21:19:50 | { ..., ... } : F [field Field1] : Object | +| F.cs:19:32:19:48 | call to method Source : Object | F.cs:19:21:19:50 | { ..., ... } : F [field Field1] : Object | +| F.cs:20:14:20:14 | access to local variable f : F [field Field1] : Object | F.cs:20:14:20:21 | access to field Field1 | | F.cs:20:14:20:14 | access to local variable f : F [field Field1] : Object | F.cs:20:14:20:21 | access to field Field1 | | F.cs:23:21:23:50 | { ..., ... } : F [field Field2] : Object | F.cs:25:14:25:14 | access to local variable f : F [field Field2] : Object | +| F.cs:23:21:23:50 | { ..., ... } : F [field Field2] : Object | F.cs:25:14:25:14 | access to local variable f : F [field Field2] : Object | +| F.cs:23:32:23:48 | call to method Source : Object | F.cs:23:21:23:50 | { ..., ... } : F [field Field2] : Object | | F.cs:23:32:23:48 | call to method Source : Object | F.cs:23:21:23:50 | { ..., ... } : F [field Field2] : Object | | F.cs:25:14:25:14 | access to local variable f : F [field Field2] : Object | F.cs:25:14:25:21 | access to field Field2 | +| F.cs:25:14:25:14 | access to local variable f : F [field Field2] : Object | F.cs:25:14:25:21 | access to field Field2 | +| F.cs:30:17:30:33 | call to method Source : Object | F.cs:32:27:32:27 | access to local variable o : Object | | F.cs:30:17:30:33 | call to method Source : Object | F.cs:32:27:32:27 | access to local variable o : Object | | F.cs:32:17:32:40 | { ..., ... } : <>__AnonType0 [property X] : Object | F.cs:33:14:33:14 | access to local variable a : <>__AnonType0 [property X] : Object | +| F.cs:32:17:32:40 | { ..., ... } : <>__AnonType0 [property X] : Object | F.cs:33:14:33:14 | access to local variable a : <>__AnonType0 [property X] : Object | +| F.cs:32:27:32:27 | access to local variable o : Object | F.cs:32:17:32:40 | { ..., ... } : <>__AnonType0 [property X] : Object | | F.cs:32:27:32:27 | access to local variable o : Object | F.cs:32:17:32:40 | { ..., ... } : <>__AnonType0 [property X] : Object | | F.cs:33:14:33:14 | access to local variable a : <>__AnonType0 [property X] : Object | F.cs:33:14:33:16 | access to property X | +| F.cs:33:14:33:14 | access to local variable a : <>__AnonType0 [property X] : Object | F.cs:33:14:33:16 | access to property X | +| G.cs:7:18:7:32 | call to method Source : Elem | G.cs:9:23:9:23 | access to local variable e : Elem | | G.cs:7:18:7:32 | call to method Source : Elem | G.cs:9:23:9:23 | access to local variable e : Elem | | G.cs:9:9:9:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:10:18:10:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:9:9:9:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:10:18:10:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:9:9:9:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | G.cs:9:9:9:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:9:9:9:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | G.cs:9:9:9:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:9:23:9:23 | access to local variable e : Elem | G.cs:9:9:9:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | +| G.cs:9:23:9:23 | access to local variable e : Elem | G.cs:9:9:9:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | +| G.cs:10:18:10:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | | G.cs:10:18:10:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | | G.cs:15:18:15:32 | call to method Source : Elem | G.cs:17:24:17:24 | access to local variable e : Elem | +| G.cs:15:18:15:32 | call to method Source : Elem | G.cs:17:24:17:24 | access to local variable e : Elem | +| G.cs:17:9:17:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:18:18:18:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:17:9:17:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:18:18:18:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:17:9:17:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | G.cs:17:9:17:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:17:9:17:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | G.cs:17:9:17:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:17:24:17:24 | access to local variable e : Elem | G.cs:17:9:17:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | | G.cs:17:24:17:24 | access to local variable e : Elem | G.cs:17:9:17:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | | G.cs:17:24:17:24 | access to local variable e : Elem | G.cs:64:34:64:34 | e : Elem | +| G.cs:17:24:17:24 | access to local variable e : Elem | G.cs:64:34:64:34 | e : Elem | +| G.cs:18:18:18:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | | G.cs:18:18:18:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | | G.cs:23:18:23:32 | call to method Source : Elem | G.cs:25:28:25:28 | access to local variable e : Elem | +| G.cs:23:18:23:32 | call to method Source : Elem | G.cs:25:28:25:28 | access to local variable e : Elem | +| G.cs:25:9:25:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:26:18:26:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:25:9:25:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:26:18:26:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:25:9:25:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | G.cs:25:9:25:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:25:9:25:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | G.cs:25:9:25:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:25:28:25:28 | access to local variable e : Elem | G.cs:25:9:25:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | | G.cs:25:28:25:28 | access to local variable e : Elem | G.cs:25:9:25:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | | G.cs:26:18:26:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | +| G.cs:26:18:26:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | +| G.cs:31:18:31:32 | call to method Source : Elem | G.cs:33:29:33:29 | access to local variable e : Elem | | G.cs:31:18:31:32 | call to method Source : Elem | G.cs:33:29:33:29 | access to local variable e : Elem | | G.cs:33:9:33:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:34:18:34:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:33:9:33:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:34:18:34:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:33:9:33:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | G.cs:33:9:33:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:33:9:33:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | G.cs:33:9:33:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:33:29:33:29 | access to local variable e : Elem | G.cs:33:9:33:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | +| G.cs:33:29:33:29 | access to local variable e : Elem | G.cs:33:9:33:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | +| G.cs:33:29:33:29 | access to local variable e : Elem | G.cs:64:34:64:34 | e : Elem | | G.cs:33:29:33:29 | access to local variable e : Elem | G.cs:64:34:64:34 | e : Elem | | G.cs:34:18:34:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | +| G.cs:34:18:34:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | +| G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | G.cs:39:14:39:15 | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | | G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | G.cs:39:14:39:15 | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | | G.cs:39:14:39:15 | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | +| G.cs:39:14:39:15 | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | +| G.cs:39:14:39:15 | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | G.cs:71:21:71:27 | this : Box2 [field Box1, field Elem] : Elem | | G.cs:39:14:39:15 | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | G.cs:71:21:71:27 | this : Box2 [field Box1, field Elem] : Elem | | G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | G.cs:39:14:39:35 | call to method GetElem | +| G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | G.cs:39:14:39:35 | call to method GetElem | +| G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | G.cs:63:21:63:27 | this : Box1 [field Elem] : Elem | | G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | G.cs:63:21:63:27 | this : Box1 [field Elem] : Elem | | G.cs:44:18:44:32 | call to method Source : Elem | G.cs:46:30:46:30 | access to local variable e : Elem | +| G.cs:44:18:44:32 | call to method Source : Elem | G.cs:46:30:46:30 | access to local variable e : Elem | +| G.cs:46:9:46:16 | [post] access to field boxfield : Box2 [field Box1, field Elem] : Elem | G.cs:46:9:46:16 | [post] this access : G [field boxfield, field Box1, field Elem] : Elem | | G.cs:46:9:46:16 | [post] access to field boxfield : Box2 [field Box1, field Elem] : Elem | G.cs:46:9:46:16 | [post] this access : G [field boxfield, field Box1, field Elem] : Elem | | G.cs:46:9:46:16 | [post] this access : G [field boxfield, field Box1, field Elem] : Elem | G.cs:47:9:47:13 | this access : G [field boxfield, field Box1, field Elem] : Elem | +| G.cs:46:9:46:16 | [post] this access : G [field boxfield, field Box1, field Elem] : Elem | G.cs:47:9:47:13 | this access : G [field boxfield, field Box1, field Elem] : Elem | +| G.cs:46:9:46:21 | [post] access to field Box1 : Box1 [field Elem] : Elem | G.cs:46:9:46:16 | [post] access to field boxfield : Box2 [field Box1, field Elem] : Elem | | G.cs:46:9:46:21 | [post] access to field Box1 : Box1 [field Elem] : Elem | G.cs:46:9:46:16 | [post] access to field boxfield : Box2 [field Box1, field Elem] : Elem | | G.cs:46:30:46:30 | access to local variable e : Elem | G.cs:46:9:46:21 | [post] access to field Box1 : Box1 [field Elem] : Elem | +| G.cs:46:30:46:30 | access to local variable e : Elem | G.cs:46:9:46:21 | [post] access to field Box1 : Box1 [field Elem] : Elem | +| G.cs:47:9:47:13 | this access : G [field boxfield, field Box1, field Elem] : Elem | G.cs:50:18:50:20 | this : G [field boxfield, field Box1, field Elem] : Elem | | G.cs:47:9:47:13 | this access : G [field boxfield, field Box1, field Elem] : Elem | G.cs:50:18:50:20 | this : G [field boxfield, field Box1, field Elem] : Elem | | G.cs:50:18:50:20 | this : G [field boxfield, field Box1, field Elem] : Elem | G.cs:52:14:52:21 | this access : G [field boxfield, field Box1, field Elem] : Elem | +| G.cs:50:18:50:20 | this : G [field boxfield, field Box1, field Elem] : Elem | G.cs:52:14:52:21 | this access : G [field boxfield, field Box1, field Elem] : Elem | +| G.cs:52:14:52:21 | access to field boxfield : Box2 [field Box1, field Elem] : Elem | G.cs:52:14:52:26 | access to field Box1 : Box1 [field Elem] : Elem | | G.cs:52:14:52:21 | access to field boxfield : Box2 [field Box1, field Elem] : Elem | G.cs:52:14:52:26 | access to field Box1 : Box1 [field Elem] : Elem | | G.cs:52:14:52:21 | this access : G [field boxfield, field Box1, field Elem] : Elem | G.cs:52:14:52:21 | access to field boxfield : Box2 [field Box1, field Elem] : Elem | +| G.cs:52:14:52:21 | this access : G [field boxfield, field Box1, field Elem] : Elem | G.cs:52:14:52:21 | access to field boxfield : Box2 [field Box1, field Elem] : Elem | +| G.cs:52:14:52:26 | access to field Box1 : Box1 [field Elem] : Elem | G.cs:52:14:52:31 | access to field Elem | | G.cs:52:14:52:26 | access to field Box1 : Box1 [field Elem] : Elem | G.cs:52:14:52:31 | access to field Elem | | G.cs:63:21:63:27 | this : Box1 [field Elem] : Elem | G.cs:63:34:63:37 | this access : Box1 [field Elem] : Elem | +| G.cs:63:21:63:27 | this : Box1 [field Elem] : Elem | G.cs:63:34:63:37 | this access : Box1 [field Elem] : Elem | +| G.cs:63:34:63:37 | this access : Box1 [field Elem] : Elem | G.cs:63:34:63:37 | access to field Elem : Elem | | G.cs:63:34:63:37 | this access : Box1 [field Elem] : Elem | G.cs:63:34:63:37 | access to field Elem : Elem | | G.cs:64:34:64:34 | e : Elem | G.cs:64:46:64:46 | access to parameter e : Elem | +| G.cs:64:34:64:34 | e : Elem | G.cs:64:46:64:46 | access to parameter e : Elem | +| G.cs:64:46:64:46 | access to parameter e : Elem | G.cs:64:39:64:42 | [post] this access : Box1 [field Elem] : Elem | | G.cs:64:46:64:46 | access to parameter e : Elem | G.cs:64:39:64:42 | [post] this access : Box1 [field Elem] : Elem | | G.cs:71:21:71:27 | this : Box2 [field Box1, field Elem] : Elem | G.cs:71:34:71:37 | this access : Box2 [field Box1, field Elem] : Elem | +| G.cs:71:21:71:27 | this : Box2 [field Box1, field Elem] : Elem | G.cs:71:34:71:37 | this access : Box2 [field Box1, field Elem] : Elem | +| G.cs:71:34:71:37 | this access : Box2 [field Box1, field Elem] : Elem | G.cs:71:34:71:37 | access to field Box1 : Box1 [field Elem] : Elem | | G.cs:71:34:71:37 | this access : Box2 [field Box1, field Elem] : Elem | G.cs:71:34:71:37 | access to field Box1 : Box1 [field Elem] : Elem | | H.cs:13:15:13:15 | a : A [field FieldA] : Object | H.cs:16:22:16:22 | access to parameter a : A [field FieldA] : Object | +| H.cs:13:15:13:15 | a : A [field FieldA] : Object | H.cs:16:22:16:22 | access to parameter a : A [field FieldA] : Object | +| H.cs:16:9:16:11 | [post] access to local variable ret : A [field FieldA] : Object | H.cs:17:16:17:18 | access to local variable ret : A [field FieldA] : Object | | H.cs:16:9:16:11 | [post] access to local variable ret : A [field FieldA] : Object | H.cs:17:16:17:18 | access to local variable ret : A [field FieldA] : Object | | H.cs:16:22:16:22 | access to parameter a : A [field FieldA] : Object | H.cs:16:22:16:29 | access to field FieldA : Object | +| H.cs:16:22:16:22 | access to parameter a : A [field FieldA] : Object | H.cs:16:22:16:29 | access to field FieldA : Object | +| H.cs:16:22:16:29 | access to field FieldA : Object | H.cs:16:9:16:11 | [post] access to local variable ret : A [field FieldA] : Object | | H.cs:16:22:16:29 | access to field FieldA : Object | H.cs:16:9:16:11 | [post] access to local variable ret : A [field FieldA] : Object | | H.cs:23:9:23:9 | [post] access to local variable a : A [field FieldA] : Object | H.cs:24:27:24:27 | access to local variable a : A [field FieldA] : Object | +| H.cs:23:9:23:9 | [post] access to local variable a : A [field FieldA] : Object | H.cs:24:27:24:27 | access to local variable a : A [field FieldA] : Object | +| H.cs:23:20:23:36 | call to method Source : Object | H.cs:23:9:23:9 | [post] access to local variable a : A [field FieldA] : Object | | H.cs:23:20:23:36 | call to method Source : Object | H.cs:23:9:23:9 | [post] access to local variable a : A [field FieldA] : Object | | H.cs:24:21:24:28 | call to method Clone : A [field FieldA] : Object | H.cs:25:14:25:18 | access to local variable clone : A [field FieldA] : Object | +| H.cs:24:21:24:28 | call to method Clone : A [field FieldA] : Object | H.cs:25:14:25:18 | access to local variable clone : A [field FieldA] : Object | +| H.cs:24:27:24:27 | access to local variable a : A [field FieldA] : Object | H.cs:13:15:13:15 | a : A [field FieldA] : Object | | H.cs:24:27:24:27 | access to local variable a : A [field FieldA] : Object | H.cs:13:15:13:15 | a : A [field FieldA] : Object | | H.cs:24:27:24:27 | access to local variable a : A [field FieldA] : Object | H.cs:24:21:24:28 | call to method Clone : A [field FieldA] : Object | +| H.cs:24:27:24:27 | access to local variable a : A [field FieldA] : Object | H.cs:24:21:24:28 | call to method Clone : A [field FieldA] : Object | +| H.cs:25:14:25:18 | access to local variable clone : A [field FieldA] : Object | H.cs:25:14:25:25 | access to field FieldA | | H.cs:25:14:25:18 | access to local variable clone : A [field FieldA] : Object | H.cs:25:14:25:25 | access to field FieldA | | H.cs:33:19:33:19 | a : A [field FieldA] : A | H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : A | +| H.cs:33:19:33:19 | a : A [field FieldA] : A | H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : A | +| H.cs:33:19:33:19 | a : A [field FieldA] : Object | H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : Object | | H.cs:33:19:33:19 | a : A [field FieldA] : Object | H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : Object | | H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : A | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : A | +| H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : A | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : A | +| H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : Object | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : Object | | H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : Object | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : Object | | H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : A | H.cs:36:20:36:27 | access to field FieldA : A | +| H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : A | H.cs:36:20:36:27 | access to field FieldA : A | +| H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : Object | H.cs:36:20:36:27 | access to field FieldA : Object | | H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : Object | H.cs:36:20:36:27 | access to field FieldA : Object | | H.cs:36:20:36:27 | access to field FieldA : A | H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : A | +| H.cs:36:20:36:27 | access to field FieldA : A | H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : A | +| H.cs:36:20:36:27 | access to field FieldA : Object | H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : Object | | H.cs:36:20:36:27 | access to field FieldA : Object | H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : Object | | H.cs:43:9:43:9 | [post] access to local variable a : A [field FieldA] : Object | H.cs:44:27:44:27 | access to local variable a : A [field FieldA] : Object | +| H.cs:43:9:43:9 | [post] access to local variable a : A [field FieldA] : Object | H.cs:44:27:44:27 | access to local variable a : A [field FieldA] : Object | +| H.cs:43:20:43:36 | call to method Source : Object | H.cs:43:9:43:9 | [post] access to local variable a : A [field FieldA] : Object | | H.cs:43:20:43:36 | call to method Source : Object | H.cs:43:9:43:9 | [post] access to local variable a : A [field FieldA] : Object | | H.cs:44:17:44:28 | call to method Transform : B [field FieldB] : Object | H.cs:45:14:45:14 | access to local variable b : B [field FieldB] : Object | +| H.cs:44:17:44:28 | call to method Transform : B [field FieldB] : Object | H.cs:45:14:45:14 | access to local variable b : B [field FieldB] : Object | +| H.cs:44:27:44:27 | access to local variable a : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | | H.cs:44:27:44:27 | access to local variable a : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | | H.cs:44:27:44:27 | access to local variable a : A [field FieldA] : Object | H.cs:44:17:44:28 | call to method Transform : B [field FieldB] : Object | +| H.cs:44:27:44:27 | access to local variable a : A [field FieldA] : Object | H.cs:44:17:44:28 | call to method Transform : B [field FieldB] : Object | +| H.cs:45:14:45:14 | access to local variable b : B [field FieldB] : Object | H.cs:45:14:45:21 | access to field FieldB | | H.cs:45:14:45:14 | access to local variable b : B [field FieldB] : Object | H.cs:45:14:45:21 | access to field FieldB | | H.cs:53:25:53:25 | a : A [field FieldA] : Object | H.cs:55:21:55:21 | access to parameter a : A [field FieldA] : Object | +| H.cs:53:25:53:25 | a : A [field FieldA] : Object | H.cs:55:21:55:21 | access to parameter a : A [field FieldA] : Object | +| H.cs:55:21:55:21 | access to parameter a : A [field FieldA] : Object | H.cs:55:21:55:28 | access to field FieldA : Object | | H.cs:55:21:55:21 | access to parameter a : A [field FieldA] : Object | H.cs:55:21:55:28 | access to field FieldA : Object | | H.cs:55:21:55:28 | access to field FieldA : Object | H.cs:55:9:55:10 | [post] access to parameter b1 : B [field FieldB] : Object | +| H.cs:55:21:55:28 | access to field FieldA : Object | H.cs:55:9:55:10 | [post] access to parameter b1 : B [field FieldB] : Object | +| H.cs:63:9:63:9 | [post] access to local variable a : A [field FieldA] : Object | H.cs:64:22:64:22 | access to local variable a : A [field FieldA] : Object | | H.cs:63:9:63:9 | [post] access to local variable a : A [field FieldA] : Object | H.cs:64:22:64:22 | access to local variable a : A [field FieldA] : Object | | H.cs:63:20:63:36 | call to method Source : Object | H.cs:63:9:63:9 | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:63:20:63:36 | call to method Source : Object | H.cs:63:9:63:9 | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:64:22:64:22 | access to local variable a : A [field FieldA] : Object | H.cs:53:25:53:25 | a : A [field FieldA] : Object | | H.cs:64:22:64:22 | access to local variable a : A [field FieldA] : Object | H.cs:53:25:53:25 | a : A [field FieldA] : Object | | H.cs:64:22:64:22 | access to local variable a : A [field FieldA] : Object | H.cs:64:25:64:26 | [post] access to local variable b1 : B [field FieldB] : Object | +| H.cs:64:22:64:22 | access to local variable a : A [field FieldA] : Object | H.cs:64:25:64:26 | [post] access to local variable b1 : B [field FieldB] : Object | +| H.cs:64:25:64:26 | [post] access to local variable b1 : B [field FieldB] : Object | H.cs:65:14:65:15 | access to local variable b1 : B [field FieldB] : Object | | H.cs:64:25:64:26 | [post] access to local variable b1 : B [field FieldB] : Object | H.cs:65:14:65:15 | access to local variable b1 : B [field FieldB] : Object | | H.cs:65:14:65:15 | access to local variable b1 : B [field FieldB] : Object | H.cs:65:14:65:22 | access to field FieldB | +| H.cs:65:14:65:15 | access to local variable b1 : B [field FieldB] : Object | H.cs:65:14:65:22 | access to field FieldB | +| H.cs:77:30:77:30 | o : Object | H.cs:79:20:79:20 | access to parameter o : Object | | H.cs:77:30:77:30 | o : Object | H.cs:79:20:79:20 | access to parameter o : Object | | H.cs:79:9:79:9 | [post] access to parameter a : A [field FieldA] : Object | H.cs:80:22:80:22 | access to parameter a : A [field FieldA] : Object | +| H.cs:79:9:79:9 | [post] access to parameter a : A [field FieldA] : Object | H.cs:80:22:80:22 | access to parameter a : A [field FieldA] : Object | +| H.cs:79:20:79:20 | access to parameter o : Object | H.cs:79:9:79:9 | [post] access to parameter a : A [field FieldA] : Object | | H.cs:79:20:79:20 | access to parameter o : Object | H.cs:79:9:79:9 | [post] access to parameter a : A [field FieldA] : Object | | H.cs:80:22:80:22 | access to parameter a : A [field FieldA] : Object | H.cs:53:25:53:25 | a : A [field FieldA] : Object | +| H.cs:80:22:80:22 | access to parameter a : A [field FieldA] : Object | H.cs:53:25:53:25 | a : A [field FieldA] : Object | +| H.cs:80:22:80:22 | access to parameter a : A [field FieldA] : Object | H.cs:80:25:80:26 | [post] access to parameter b1 : B [field FieldB] : Object | | H.cs:80:22:80:22 | access to parameter a : A [field FieldA] : Object | H.cs:80:25:80:26 | [post] access to parameter b1 : B [field FieldB] : Object | | H.cs:88:17:88:17 | [post] access to local variable a : A [field FieldA] : Object | H.cs:89:14:89:14 | access to local variable a : A [field FieldA] : Object | +| H.cs:88:17:88:17 | [post] access to local variable a : A [field FieldA] : Object | H.cs:89:14:89:14 | access to local variable a : A [field FieldA] : Object | +| H.cs:88:20:88:36 | call to method Source : Object | H.cs:77:30:77:30 | o : Object | | H.cs:88:20:88:36 | call to method Source : Object | H.cs:77:30:77:30 | o : Object | | H.cs:88:20:88:36 | call to method Source : Object | H.cs:88:17:88:17 | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:88:20:88:36 | call to method Source : Object | H.cs:88:17:88:17 | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:88:20:88:36 | call to method Source : Object | H.cs:88:39:88:40 | [post] access to local variable b1 : B [field FieldB] : Object | | H.cs:88:20:88:36 | call to method Source : Object | H.cs:88:39:88:40 | [post] access to local variable b1 : B [field FieldB] : Object | | H.cs:88:39:88:40 | [post] access to local variable b1 : B [field FieldB] : Object | H.cs:90:14:90:15 | access to local variable b1 : B [field FieldB] : Object | +| H.cs:88:39:88:40 | [post] access to local variable b1 : B [field FieldB] : Object | H.cs:90:14:90:15 | access to local variable b1 : B [field FieldB] : Object | +| H.cs:89:14:89:14 | access to local variable a : A [field FieldA] : Object | H.cs:89:14:89:21 | access to field FieldA | | H.cs:89:14:89:14 | access to local variable a : A [field FieldA] : Object | H.cs:89:14:89:21 | access to field FieldA | | H.cs:90:14:90:15 | access to local variable b1 : B [field FieldB] : Object | H.cs:90:14:90:22 | access to field FieldB | +| H.cs:90:14:90:15 | access to local variable b1 : B [field FieldB] : Object | H.cs:90:14:90:22 | access to field FieldB | +| H.cs:102:23:102:23 | a : A [field FieldA] : Object | H.cs:105:23:105:23 | access to parameter a : A [field FieldA] : Object | | H.cs:102:23:102:23 | a : A [field FieldA] : Object | H.cs:105:23:105:23 | access to parameter a : A [field FieldA] : Object | | H.cs:105:9:105:12 | [post] access to local variable temp : B [field FieldB, field FieldA] : Object | H.cs:106:29:106:32 | access to local variable temp : B [field FieldB, field FieldA] : Object | +| H.cs:105:9:105:12 | [post] access to local variable temp : B [field FieldB, field FieldA] : Object | H.cs:106:29:106:32 | access to local variable temp : B [field FieldB, field FieldA] : Object | +| H.cs:105:23:105:23 | access to parameter a : A [field FieldA] : Object | H.cs:105:9:105:12 | [post] access to local variable temp : B [field FieldB, field FieldA] : Object | | H.cs:105:23:105:23 | access to parameter a : A [field FieldA] : Object | H.cs:105:9:105:12 | [post] access to local variable temp : B [field FieldB, field FieldA] : Object | | H.cs:106:26:106:39 | (...) ... : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | +| H.cs:106:26:106:39 | (...) ... : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | +| H.cs:106:26:106:39 | (...) ... : A [field FieldA] : Object | H.cs:106:16:106:40 | call to method Transform : B [field FieldB] : Object | | H.cs:106:26:106:39 | (...) ... : A [field FieldA] : Object | H.cs:106:16:106:40 | call to method Transform : B [field FieldB] : Object | | H.cs:106:29:106:32 | access to local variable temp : B [field FieldB, field FieldA] : Object | H.cs:106:29:106:39 | access to field FieldB : A [field FieldA] : Object | +| H.cs:106:29:106:32 | access to local variable temp : B [field FieldB, field FieldA] : Object | H.cs:106:29:106:39 | access to field FieldB : A [field FieldA] : Object | +| H.cs:106:29:106:39 | access to field FieldB : A [field FieldA] : Object | H.cs:106:26:106:39 | (...) ... : A [field FieldA] : Object | | H.cs:106:29:106:39 | access to field FieldB : A [field FieldA] : Object | H.cs:106:26:106:39 | (...) ... : A [field FieldA] : Object | | H.cs:112:9:112:9 | [post] access to local variable a : A [field FieldA] : Object | H.cs:113:31:113:31 | access to local variable a : A [field FieldA] : Object | +| H.cs:112:9:112:9 | [post] access to local variable a : A [field FieldA] : Object | H.cs:113:31:113:31 | access to local variable a : A [field FieldA] : Object | +| H.cs:112:20:112:36 | call to method Source : Object | H.cs:112:9:112:9 | [post] access to local variable a : A [field FieldA] : Object | | H.cs:112:20:112:36 | call to method Source : Object | H.cs:112:9:112:9 | [post] access to local variable a : A [field FieldA] : Object | | H.cs:113:17:113:32 | call to method TransformWrap : B [field FieldB] : Object | H.cs:114:14:114:14 | access to local variable b : B [field FieldB] : Object | +| H.cs:113:17:113:32 | call to method TransformWrap : B [field FieldB] : Object | H.cs:114:14:114:14 | access to local variable b : B [field FieldB] : Object | +| H.cs:113:31:113:31 | access to local variable a : A [field FieldA] : Object | H.cs:102:23:102:23 | a : A [field FieldA] : Object | | H.cs:113:31:113:31 | access to local variable a : A [field FieldA] : Object | H.cs:102:23:102:23 | a : A [field FieldA] : Object | | H.cs:113:31:113:31 | access to local variable a : A [field FieldA] : Object | H.cs:113:17:113:32 | call to method TransformWrap : B [field FieldB] : Object | +| H.cs:113:31:113:31 | access to local variable a : A [field FieldA] : Object | H.cs:113:17:113:32 | call to method TransformWrap : B [field FieldB] : Object | +| H.cs:114:14:114:14 | access to local variable b : B [field FieldB] : Object | H.cs:114:14:114:21 | access to field FieldB | | H.cs:114:14:114:14 | access to local variable b : B [field FieldB] : Object | H.cs:114:14:114:21 | access to field FieldB | | H.cs:122:18:122:18 | a : A [field FieldA] : Object | H.cs:124:26:124:26 | access to parameter a : A [field FieldA] : Object | +| H.cs:122:18:122:18 | a : A [field FieldA] : Object | H.cs:124:26:124:26 | access to parameter a : A [field FieldA] : Object | +| H.cs:124:16:124:27 | call to method Transform : B [field FieldB] : Object | H.cs:124:16:124:34 | access to field FieldB : Object | | H.cs:124:16:124:27 | call to method Transform : B [field FieldB] : Object | H.cs:124:16:124:34 | access to field FieldB : Object | | H.cs:124:26:124:26 | access to parameter a : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | +| H.cs:124:26:124:26 | access to parameter a : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | +| H.cs:124:26:124:26 | access to parameter a : A [field FieldA] : Object | H.cs:124:16:124:27 | call to method Transform : B [field FieldB] : Object | | H.cs:124:26:124:26 | access to parameter a : A [field FieldA] : Object | H.cs:124:16:124:27 | call to method Transform : B [field FieldB] : Object | | H.cs:130:9:130:9 | [post] access to local variable a : A [field FieldA] : Object | H.cs:131:18:131:18 | access to local variable a : A [field FieldA] : Object | +| H.cs:130:9:130:9 | [post] access to local variable a : A [field FieldA] : Object | H.cs:131:18:131:18 | access to local variable a : A [field FieldA] : Object | +| H.cs:130:20:130:36 | call to method Source : Object | H.cs:130:9:130:9 | [post] access to local variable a : A [field FieldA] : Object | | H.cs:130:20:130:36 | call to method Source : Object | H.cs:130:9:130:9 | [post] access to local variable a : A [field FieldA] : Object | | H.cs:131:18:131:18 | access to local variable a : A [field FieldA] : Object | H.cs:122:18:122:18 | a : A [field FieldA] : Object | +| H.cs:131:18:131:18 | access to local variable a : A [field FieldA] : Object | H.cs:122:18:122:18 | a : A [field FieldA] : Object | +| H.cs:131:18:131:18 | access to local variable a : A [field FieldA] : Object | H.cs:131:14:131:19 | call to method Get | | H.cs:131:18:131:18 | access to local variable a : A [field FieldA] : Object | H.cs:131:14:131:19 | call to method Get | | H.cs:138:27:138:27 | o : A | H.cs:141:20:141:25 | ... as ... : A | +| H.cs:138:27:138:27 | o : A | H.cs:141:20:141:25 | ... as ... : A | +| H.cs:141:9:141:9 | [post] access to local variable a : A [field FieldA] : A | H.cs:142:26:142:26 | access to local variable a : A [field FieldA] : A | | H.cs:141:9:141:9 | [post] access to local variable a : A [field FieldA] : A | H.cs:142:26:142:26 | access to local variable a : A [field FieldA] : A | | H.cs:141:20:141:25 | ... as ... : A | H.cs:141:9:141:9 | [post] access to local variable a : A [field FieldA] : A | +| H.cs:141:20:141:25 | ... as ... : A | H.cs:141:9:141:9 | [post] access to local variable a : A [field FieldA] : A | +| H.cs:142:16:142:27 | call to method Transform : B [field FieldB] : A | H.cs:142:16:142:34 | access to field FieldB : A | | H.cs:142:16:142:27 | call to method Transform : B [field FieldB] : A | H.cs:142:16:142:34 | access to field FieldB : A | | H.cs:142:26:142:26 | access to local variable a : A [field FieldA] : A | H.cs:33:19:33:19 | a : A [field FieldA] : A | +| H.cs:142:26:142:26 | access to local variable a : A [field FieldA] : A | H.cs:33:19:33:19 | a : A [field FieldA] : A | +| H.cs:142:26:142:26 | access to local variable a : A [field FieldA] : A | H.cs:142:16:142:27 | call to method Transform : B [field FieldB] : A | | H.cs:142:26:142:26 | access to local variable a : A [field FieldA] : A | H.cs:142:16:142:27 | call to method Transform : B [field FieldB] : A | | H.cs:147:17:147:39 | call to method Through : A | H.cs:148:14:148:14 | access to local variable a | +| H.cs:147:17:147:39 | call to method Through : A | H.cs:148:14:148:14 | access to local variable a | +| H.cs:147:25:147:38 | call to method Source : A | H.cs:138:27:138:27 | o : A | | H.cs:147:25:147:38 | call to method Source : A | H.cs:138:27:138:27 | o : A | | H.cs:147:25:147:38 | call to method Source : A | H.cs:147:17:147:39 | call to method Through : A | +| H.cs:147:25:147:38 | call to method Source : A | H.cs:147:17:147:39 | call to method Through : A | +| H.cs:153:32:153:32 | o : Object | H.cs:156:20:156:20 | access to parameter o : Object | | H.cs:153:32:153:32 | o : Object | H.cs:156:20:156:20 | access to parameter o : Object | | H.cs:155:17:155:30 | call to method Source : B | H.cs:156:9:156:9 | access to local variable b : B | +| H.cs:155:17:155:30 | call to method Source : B | H.cs:156:9:156:9 | access to local variable b : B | +| H.cs:156:9:156:9 | [post] access to local variable b : B [field FieldB] : Object | H.cs:157:20:157:20 | access to local variable b : B [field FieldB] : Object | | H.cs:156:9:156:9 | [post] access to local variable b : B [field FieldB] : Object | H.cs:157:20:157:20 | access to local variable b : B [field FieldB] : Object | | H.cs:156:9:156:9 | access to local variable b : B | H.cs:157:20:157:20 | access to local variable b : B | +| H.cs:156:9:156:9 | access to local variable b : B | H.cs:157:20:157:20 | access to local variable b : B | +| H.cs:156:20:156:20 | access to parameter o : Object | H.cs:156:9:156:9 | [post] access to local variable b : B [field FieldB] : Object | | H.cs:156:20:156:20 | access to parameter o : Object | H.cs:156:9:156:9 | [post] access to local variable b : B [field FieldB] : Object | | H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA] : B | H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA] : B | +| H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA] : B | H.cs:164:19:164:19 | [post] access to local variable a : A [field 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 : A [field 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 : A [field FieldA] : B | | H.cs:157:20:157:20 | access to local variable b : B [field FieldB] : Object | H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA, field FieldB] : Object | +| H.cs:157:20:157:20 | access to local variable b : B [field FieldB] : Object | H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA, field FieldB] : Object | +| H.cs:163:17:163:35 | call to method Source : Object | H.cs:164:22:164:22 | access to local variable o : Object | | H.cs:163:17:163:35 | call to method Source : 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 : A [field FieldA, field FieldB] : Object | H.cs:165:20:165:20 | access to local variable a : A [field FieldA, field FieldB] : Object | +| H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA, field FieldB] : Object | H.cs:165:20:165:20 | access to local variable a : A [field FieldA, field FieldB] : Object | +| H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA] : B | H.cs:165:20:165:20 | access to local variable a : A [field FieldA] : B | | H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA] : B | H.cs:165:20:165:20 | access to local variable a : A [field FieldA] : B | | H.cs:164:22:164:22 | access to local variable o : Object | H.cs:153:32:153:32 | o : Object | +| H.cs:164:22:164:22 | access to local variable o : Object | H.cs:153:32:153:32 | o : 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 : A [field FieldA, field FieldB] : 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 : A [field FieldA, field FieldB] : Object | | H.cs:165:17:165:27 | (...) ... : B | H.cs:166:14:166:14 | access to local variable b | +| H.cs:165:17:165:27 | (...) ... : B | H.cs:166:14:166:14 | access to local variable b | +| H.cs:165:17:165:27 | (...) ... : B [field FieldB] : Object | H.cs:167:14:167:14 | access to local variable b : B [field FieldB] : Object | | H.cs:165:17:165:27 | (...) ... : B [field FieldB] : Object | H.cs:167:14:167:14 | access to local variable b : B [field FieldB] : Object | | H.cs:165:20:165:20 | access to local variable a : A [field FieldA, field FieldB] : Object | H.cs:165:20:165:27 | access to field FieldA : B [field FieldB] : Object | +| H.cs:165:20:165:20 | access to local variable a : A [field FieldA, field FieldB] : Object | H.cs:165:20:165:27 | access to field FieldA : B [field FieldB] : Object | +| H.cs:165:20:165:20 | access to local variable a : A [field FieldA] : B | H.cs:165:20:165:27 | access to field FieldA : B | | H.cs:165:20:165:20 | access to local variable a : A [field FieldA] : B | H.cs:165:20:165:27 | access to field FieldA : B | | H.cs:165:20:165:27 | access to field FieldA : B | H.cs:165:17:165:27 | (...) ... : B | +| H.cs:165:20:165:27 | access to field FieldA : B | H.cs:165:17:165:27 | (...) ... : B | +| H.cs:165:20:165:27 | access to field FieldA : B [field FieldB] : Object | H.cs:165:17:165:27 | (...) ... : B [field FieldB] : Object | | H.cs:165:20:165:27 | access to field FieldA : B [field FieldB] : Object | H.cs:165:17:165:27 | (...) ... : B [field FieldB] : Object | | H.cs:167:14:167:14 | access to local variable b : B [field FieldB] : Object | H.cs:167:14:167:21 | access to field FieldB | +| H.cs:167:14:167:14 | access to local variable b : B [field FieldB] : Object | H.cs:167:14:167:21 | access to field FieldB | +| I.cs:7:9:7:14 | [post] this access : I [field Field1] : Object | I.cs:21:13:21:19 | object creation of type I : I [field Field1] : Object | | I.cs:7:9:7:14 | [post] this access : I [field Field1] : Object | I.cs:21:13:21:19 | object creation of type I : I [field Field1] : Object | | I.cs:7:9:7:14 | [post] this access : I [field Field1] : Object | I.cs:26:13:26:37 | [pre-initializer] object creation of type I : I [field Field1] : Object | +| I.cs:7:9:7:14 | [post] this access : I [field Field1] : Object | I.cs:26:13:26:37 | [pre-initializer] object creation of type I : I [field Field1] : Object | +| I.cs:7:18:7:34 | call to method Source : Object | I.cs:7:9:7:14 | [post] this access : I [field Field1] : Object | | I.cs:7:18:7:34 | call to method Source : Object | I.cs:7:9:7:14 | [post] this access : I [field Field1] : Object | | I.cs:13:17:13:33 | call to method Source : Object | I.cs:15:20:15:20 | access to local variable o : Object | +| I.cs:13:17:13:33 | call to method Source : Object | I.cs:15:20:15:20 | access to local variable o : Object | +| I.cs:15:9:15:9 | [post] access to local variable i : I [field Field1] : Object | I.cs:16:9:16:9 | access to local variable i : I [field Field1] : Object | | I.cs:15:9:15:9 | [post] access to local variable i : I [field Field1] : Object | I.cs:16:9:16:9 | access to local variable i : I [field Field1] : Object | | I.cs:15:20:15:20 | access to local variable o : Object | I.cs:15:9:15:9 | [post] access to local variable i : I [field Field1] : Object | +| I.cs:15:20:15:20 | access to local variable o : Object | I.cs:15:9:15:9 | [post] access to local variable i : I [field Field1] : Object | +| I.cs:16:9:16:9 | access to local variable i : I [field Field1] : Object | I.cs:17:9:17:9 | access to local variable i : I [field Field1] : Object | | I.cs:16:9:16:9 | access to local variable i : I [field Field1] : Object | I.cs:17:9:17:9 | access to local variable i : I [field Field1] : Object | | I.cs:17:9:17:9 | access to local variable i : I [field Field1] : Object | I.cs:18:14:18:14 | access to local variable i : I [field Field1] : Object | +| I.cs:17:9:17:9 | access to local variable i : I [field Field1] : Object | I.cs:18:14:18:14 | access to local variable i : I [field Field1] : Object | +| I.cs:18:14:18:14 | access to local variable i : I [field Field1] : Object | I.cs:18:14:18:21 | access to field Field1 | | I.cs:18:14:18:14 | access to local variable i : I [field Field1] : Object | I.cs:18:14:18:21 | access to field Field1 | | I.cs:21:13:21:19 | object creation of type I : I [field Field1] : Object | I.cs:22:9:22:9 | access to local variable i : I [field Field1] : Object | +| I.cs:21:13:21:19 | object creation of type I : I [field Field1] : Object | I.cs:22:9:22:9 | access to local variable i : I [field Field1] : Object | +| I.cs:22:9:22:9 | access to local variable i : I [field Field1] : Object | I.cs:23:14:23:14 | access to local variable i : I [field Field1] : Object | | I.cs:22:9:22:9 | access to local variable i : I [field Field1] : Object | I.cs:23:14:23:14 | access to local variable i : I [field Field1] : Object | | I.cs:23:14:23:14 | access to local variable i : I [field Field1] : Object | I.cs:23:14:23:21 | access to field Field1 | +| I.cs:23:14:23:14 | access to local variable i : I [field Field1] : Object | I.cs:23:14:23:21 | access to field Field1 | +| I.cs:26:13:26:37 | [pre-initializer] object creation of type I : I [field Field1] : Object | I.cs:27:14:27:14 | access to local variable i : I [field Field1] : Object | | I.cs:26:13:26:37 | [pre-initializer] object creation of type I : I [field Field1] : Object | I.cs:27:14:27:14 | access to local variable i : I [field Field1] : Object | | I.cs:27:14:27:14 | access to local variable i : I [field Field1] : Object | I.cs:27:14:27:21 | access to field Field1 | +| I.cs:27:14:27:14 | access to local variable i : I [field Field1] : Object | I.cs:27:14:27:21 | access to field Field1 | +| I.cs:31:13:31:29 | call to method Source : Object | I.cs:32:20:32:20 | access to local variable o : Object | | I.cs:31:13:31:29 | call to method Source : Object | I.cs:32:20:32:20 | access to local variable o : Object | | I.cs:32:9:32:9 | [post] access to local variable i : I [field Field1] : Object | I.cs:33:9:33:9 | access to local variable i : I [field Field1] : Object | +| I.cs:32:9:32:9 | [post] access to local variable i : I [field Field1] : Object | I.cs:33:9:33:9 | access to local variable i : I [field Field1] : Object | +| I.cs:32:20:32:20 | access to local variable o : Object | I.cs:32:9:32:9 | [post] access to local variable i : I [field Field1] : Object | | I.cs:32:20:32:20 | access to local variable o : Object | I.cs:32:9:32:9 | [post] access to local variable i : I [field Field1] : Object | | I.cs:33:9:33:9 | access to local variable i : I [field Field1] : Object | I.cs:34:12:34:12 | access to local variable i : I [field Field1] : Object | +| I.cs:33:9:33:9 | access to local variable i : I [field Field1] : Object | I.cs:34:12:34:12 | access to local variable i : I [field Field1] : Object | +| I.cs:34:12:34:12 | access to local variable i : I [field Field1] : Object | I.cs:37:23:37:23 | i : I [field Field1] : Object | | I.cs:34:12:34:12 | access to local variable i : I [field Field1] : Object | I.cs:37:23:37:23 | i : I [field Field1] : Object | | I.cs:37:23:37:23 | i : I [field Field1] : Object | I.cs:39:9:39:9 | access to parameter i : I [field Field1] : Object | +| I.cs:37:23:37:23 | i : I [field Field1] : Object | I.cs:39:9:39:9 | access to parameter i : I [field Field1] : Object | +| I.cs:39:9:39:9 | access to parameter i : I [field Field1] : Object | I.cs:40:14:40:14 | access to parameter i : I [field Field1] : Object | | I.cs:39:9:39:9 | access to parameter i : I [field Field1] : Object | I.cs:40:14:40:14 | access to parameter i : I [field Field1] : Object | | I.cs:40:14:40:14 | access to parameter i : I [field Field1] : Object | I.cs:40:14:40:21 | access to field Field1 | +| I.cs:40:14:40:14 | access to parameter i : I [field Field1] : Object | I.cs:40:14:40:21 | access to field Field1 | +| J.cs:14:26:14:30 | field : Object | J.cs:14:66:14:70 | access to parameter field : Object | | J.cs:14:26:14:30 | field : Object | J.cs:14:66:14:70 | access to parameter field : Object | | J.cs:14:40:14:43 | prop : Object | J.cs:14:73:14:76 | access to parameter prop : Object | +| J.cs:14:40:14:43 | prop : Object | J.cs:14:73:14:76 | access to parameter prop : Object | +| J.cs:14:66:14:70 | access to parameter field : Object | J.cs:14:50:14:54 | [post] this access : Struct [field Field] : Object | | J.cs:14:66:14:70 | access to parameter field : Object | J.cs:14:50:14:54 | [post] this access : Struct [field Field] : Object | | J.cs:14:73:14:76 | access to parameter prop : Object | J.cs:14:57:14:60 | [post] this access : Struct [property Prop] : Object | +| J.cs:14:73:14:76 | access to parameter prop : Object | J.cs:14:57:14:60 | [post] this access : Struct [property Prop] : Object | +| J.cs:21:17:21:33 | call to method Source : Object | J.cs:22:34:22:34 | access to local variable o : Object | | J.cs:21:17:21:33 | call to method Source : Object | J.cs:22:34:22:34 | access to local variable o : Object | | J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | J.cs:23:14:23:15 | access to local variable r1 : RecordClass [property Prop1] : Object | +| J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | J.cs:23:14:23:15 | access to local variable r1 : RecordClass [property Prop1] : Object | +| J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | J.cs:27:14:27:15 | access to local variable r2 : RecordClass [property Prop1] : Object | | J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | J.cs:27:14:27:15 | access to local variable r2 : RecordClass [property Prop1] : Object | | J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | J.cs:31:14:31:15 | access to local variable r3 : RecordClass [property Prop1] : Object | +| J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | J.cs:31:14:31:15 | access to local variable r3 : RecordClass [property Prop1] : Object | +| J.cs:22:34:22:34 | access to local variable o : Object | J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | | J.cs:22:34:22:34 | access to local variable o : Object | J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | | J.cs:23:14:23:15 | access to local variable r1 : RecordClass [property Prop1] : Object | J.cs:23:14:23:21 | access to property Prop1 | +| J.cs:23:14:23:15 | access to local variable r1 : RecordClass [property Prop1] : Object | J.cs:23:14:23:21 | access to property Prop1 | +| J.cs:27:14:27:15 | access to local variable r2 : RecordClass [property Prop1] : Object | J.cs:27:14:27:21 | access to property Prop1 | | J.cs:27:14:27:15 | access to local variable r2 : RecordClass [property Prop1] : Object | J.cs:27:14:27:21 | access to property Prop1 | | J.cs:30:18:30:54 | ... with { ... } : RecordClass [property Prop2] : Object | J.cs:32:14:32:15 | access to local variable r3 : RecordClass [property Prop2] : Object | +| J.cs:30:18:30:54 | ... with { ... } : RecordClass [property Prop2] : Object | J.cs:32:14:32:15 | access to local variable r3 : RecordClass [property Prop2] : Object | +| J.cs:30:36:30:52 | call to method Source : Object | J.cs:30:18:30:54 | ... with { ... } : RecordClass [property Prop2] : Object | | J.cs:30:36:30:52 | call to method Source : Object | J.cs:30:18:30:54 | ... with { ... } : RecordClass [property Prop2] : Object | | J.cs:31:14:31:15 | access to local variable r3 : RecordClass [property Prop1] : Object | J.cs:31:14:31:21 | access to property Prop1 | +| J.cs:31:14:31:15 | access to local variable r3 : RecordClass [property Prop1] : Object | J.cs:31:14:31:21 | access to property Prop1 | +| J.cs:32:14:32:15 | access to local variable r3 : RecordClass [property Prop2] : Object | J.cs:32:14:32:21 | access to property Prop2 | | J.cs:32:14:32:15 | access to local variable r3 : RecordClass [property Prop2] : Object | J.cs:32:14:32:21 | access to property Prop2 | | J.cs:41:17:41:33 | call to method Source : Object | J.cs:42:35:42:35 | access to local variable o : Object | +| J.cs:41:17:41:33 | call to method Source : Object | J.cs:42:35:42:35 | access to local variable o : Object | +| J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | J.cs:43:14:43:15 | access to local variable r1 : RecordStruct [property Prop1] : Object | | J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | J.cs:43:14:43:15 | access to local variable r1 : RecordStruct [property Prop1] : Object | | J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | J.cs:47:14:47:15 | access to local variable r2 : RecordStruct [property Prop1] : Object | +| J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | J.cs:47:14:47:15 | access to local variable r2 : RecordStruct [property Prop1] : Object | +| J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | J.cs:51:14:51:15 | access to local variable r3 : RecordStruct [property Prop1] : Object | | J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | J.cs:51:14:51:15 | access to local variable r3 : RecordStruct [property Prop1] : Object | | J.cs:42:35:42:35 | access to local variable o : Object | J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | +| J.cs:42:35:42:35 | access to local variable o : Object | J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | +| J.cs:43:14:43:15 | access to local variable r1 : RecordStruct [property Prop1] : Object | J.cs:43:14:43:21 | access to property Prop1 | | J.cs:43:14:43:15 | access to local variable r1 : RecordStruct [property Prop1] : Object | J.cs:43:14:43:21 | access to property Prop1 | | J.cs:47:14:47:15 | access to local variable r2 : RecordStruct [property Prop1] : Object | J.cs:47:14:47:21 | access to property Prop1 | +| J.cs:47:14:47:15 | access to local variable r2 : RecordStruct [property Prop1] : Object | J.cs:47:14:47:21 | access to property Prop1 | +| J.cs:50:18:50:54 | ... with { ... } : RecordStruct [property Prop2] : Object | J.cs:52:14:52:15 | access to local variable r3 : RecordStruct [property Prop2] : Object | | J.cs:50:18:50:54 | ... with { ... } : RecordStruct [property Prop2] : Object | J.cs:52:14:52:15 | access to local variable r3 : RecordStruct [property Prop2] : Object | | J.cs:50:36:50:52 | call to method Source : Object | J.cs:50:18:50:54 | ... with { ... } : RecordStruct [property Prop2] : Object | +| J.cs:50:36:50:52 | call to method Source : Object | J.cs:50:18:50:54 | ... with { ... } : RecordStruct [property Prop2] : Object | +| J.cs:51:14:51:15 | access to local variable r3 : RecordStruct [property Prop1] : Object | J.cs:51:14:51:21 | access to property Prop1 | | J.cs:51:14:51:15 | access to local variable r3 : RecordStruct [property Prop1] : Object | J.cs:51:14:51:21 | access to property Prop1 | | J.cs:52:14:52:15 | access to local variable r3 : RecordStruct [property Prop2] : Object | J.cs:52:14:52:21 | access to property Prop2 | +| J.cs:52:14:52:15 | access to local variable r3 : RecordStruct [property Prop2] : Object | J.cs:52:14:52:21 | access to property Prop2 | +| J.cs:61:17:61:33 | call to method Source : Object | J.cs:62:29:62:29 | access to local variable o : Object | | J.cs:61:17:61:33 | call to method Source : Object | J.cs:62:29:62:29 | access to local variable o : Object | | J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object | J.cs:65:14:65:15 | access to local variable s2 : Struct [field Field] : Object | +| J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object | J.cs:65:14:65:15 | access to local variable s2 : Struct [field Field] : Object | +| J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object | J.cs:69:14:69:15 | access to local variable s3 : Struct [field Field] : Object | | J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object | J.cs:69:14:69:15 | access to local variable s3 : Struct [field Field] : Object | | J.cs:62:29:62:29 | access to local variable o : Object | J.cs:14:26:14:30 | field : Object | +| J.cs:62:29:62:29 | access to local variable o : Object | J.cs:14:26:14:30 | field : Object | +| J.cs:62:29:62:29 | access to local variable o : Object | J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object | | J.cs:62:29:62:29 | access to local variable o : Object | J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object | | J.cs:65:14:65:15 | access to local variable s2 : Struct [field Field] : Object | J.cs:65:14:65:21 | access to field Field | +| J.cs:65:14:65:15 | access to local variable s2 : Struct [field Field] : Object | J.cs:65:14:65:21 | access to field Field | +| J.cs:68:18:68:53 | ... with { ... } : Struct [property Prop] : Object | J.cs:70:14:70:15 | access to local variable s3 : Struct [property Prop] : Object | | J.cs:68:18:68:53 | ... with { ... } : Struct [property Prop] : Object | J.cs:70:14:70:15 | access to local variable s3 : Struct [property Prop] : Object | | J.cs:68:35:68:51 | call to method Source : Object | J.cs:68:18:68:53 | ... with { ... } : Struct [property Prop] : Object | +| J.cs:68:35:68:51 | call to method Source : Object | J.cs:68:18:68:53 | ... with { ... } : Struct [property Prop] : Object | +| J.cs:69:14:69:15 | access to local variable s3 : Struct [field Field] : Object | J.cs:69:14:69:21 | access to field Field | | J.cs:69:14:69:15 | access to local variable s3 : Struct [field Field] : Object | J.cs:69:14:69:21 | access to field Field | | J.cs:70:14:70:15 | access to local variable s3 : Struct [property Prop] : Object | J.cs:70:14:70:20 | access to property Prop | +| J.cs:70:14:70:15 | access to local variable s3 : Struct [property Prop] : Object | J.cs:70:14:70:20 | access to property Prop | +| J.cs:79:17:79:33 | call to method Source : Object | J.cs:80:35:80:35 | access to local variable o : Object | | J.cs:79:17:79:33 | call to method Source : Object | J.cs:80:35:80:35 | access to local variable o : Object | | J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object | J.cs:84:14:84:15 | access to local variable s2 : Struct [property Prop] : Object | +| J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object | J.cs:84:14:84:15 | access to local variable s2 : Struct [property Prop] : Object | +| J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object | J.cs:88:14:88:15 | access to local variable s3 : Struct [property Prop] : Object | | J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object | J.cs:88:14:88:15 | access to local variable s3 : Struct [property Prop] : Object | | J.cs:80:35:80:35 | access to local variable o : Object | J.cs:14:40:14:43 | prop : Object | +| J.cs:80:35:80:35 | access to local variable o : Object | J.cs:14:40:14:43 | prop : Object | +| J.cs:80:35:80:35 | access to local variable o : Object | J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object | | J.cs:80:35:80:35 | access to local variable o : Object | J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object | | J.cs:84:14:84:15 | access to local variable s2 : Struct [property Prop] : Object | J.cs:84:14:84:20 | access to property Prop | +| J.cs:84:14:84:15 | access to local variable s2 : Struct [property Prop] : Object | J.cs:84:14:84:20 | access to property Prop | +| J.cs:86:18:86:54 | ... with { ... } : Struct [field Field] : Object | J.cs:87:14:87:15 | access to local variable s3 : Struct [field Field] : Object | | J.cs:86:18:86:54 | ... with { ... } : Struct [field Field] : Object | J.cs:87:14:87:15 | access to local variable s3 : Struct [field Field] : Object | | J.cs:86:36:86:52 | call to method Source : Object | J.cs:86:18:86:54 | ... with { ... } : Struct [field Field] : Object | +| J.cs:86:36:86:52 | call to method Source : Object | J.cs:86:18:86:54 | ... with { ... } : Struct [field Field] : Object | +| J.cs:87:14:87:15 | access to local variable s3 : Struct [field Field] : Object | J.cs:87:14:87:21 | access to field Field | | J.cs:87:14:87:15 | access to local variable s3 : Struct [field Field] : Object | J.cs:87:14:87:21 | access to field Field | | J.cs:88:14:88:15 | access to local variable s3 : Struct [property Prop] : Object | J.cs:88:14:88:20 | access to property Prop | +| J.cs:88:14:88:15 | access to local variable s3 : Struct [property Prop] : Object | J.cs:88:14:88:20 | access to property Prop | +| J.cs:97:17:97:33 | call to method Source : Object | J.cs:99:28:99:28 | access to local variable o : Object | | J.cs:97:17:97:33 | call to method Source : Object | J.cs:99:28:99:28 | access to local variable o : Object | | J.cs:99:18:99:41 | { ..., ... } : <>__AnonType0 [property X] : Object | J.cs:102:14:102:15 | access to local variable a2 : <>__AnonType0 [property X] : Object | +| J.cs:99:18:99:41 | { ..., ... } : <>__AnonType0 [property X] : Object | J.cs:102:14:102:15 | access to local variable a2 : <>__AnonType0 [property X] : Object | +| J.cs:99:18:99:41 | { ..., ... } : <>__AnonType0 [property X] : Object | J.cs:106:14:106:15 | access to local variable a3 : <>__AnonType0 [property X] : Object | | J.cs:99:18:99:41 | { ..., ... } : <>__AnonType0 [property X] : Object | J.cs:106:14:106:15 | access to local variable a3 : <>__AnonType0 [property X] : Object | | J.cs:99:28:99:28 | access to local variable o : Object | J.cs:99:18:99:41 | { ..., ... } : <>__AnonType0 [property X] : Object | +| J.cs:99:28:99:28 | access to local variable o : Object | J.cs:99:18:99:41 | { ..., ... } : <>__AnonType0 [property X] : Object | +| J.cs:102:14:102:15 | access to local variable a2 : <>__AnonType0 [property X] : Object | J.cs:102:14:102:17 | access to property X | | J.cs:102:14:102:15 | access to local variable a2 : <>__AnonType0 [property X] : Object | J.cs:102:14:102:17 | access to property X | | J.cs:105:18:105:50 | ... with { ... } : <>__AnonType0 [property Y] : Object | J.cs:107:14:107:15 | access to local variable a3 : <>__AnonType0 [property Y] : Object | +| J.cs:105:18:105:50 | ... with { ... } : <>__AnonType0 [property Y] : Object | J.cs:107:14:107:15 | access to local variable a3 : <>__AnonType0 [property Y] : Object | +| J.cs:105:32:105:48 | call to method Source : Object | J.cs:105:18:105:50 | ... with { ... } : <>__AnonType0 [property Y] : Object | | J.cs:105:32:105:48 | call to method Source : Object | J.cs:105:18:105:50 | ... with { ... } : <>__AnonType0 [property Y] : Object | | J.cs:106:14:106:15 | access to local variable a3 : <>__AnonType0 [property X] : Object | J.cs:106:14:106:17 | access to property X | +| J.cs:106:14:106:15 | access to local variable a3 : <>__AnonType0 [property X] : Object | J.cs:106:14:106:17 | access to property X | +| J.cs:107:14:107:15 | access to local variable a3 : <>__AnonType0 [property Y] : Object | J.cs:107:14:107:17 | access to property Y | | J.cs:107:14:107:15 | access to local variable a3 : <>__AnonType0 [property Y] : Object | J.cs:107:14:107:17 | access to property Y | | J.cs:119:13:119:13 | [post] access to local variable a : Int32[] [element] : Int32 | J.cs:125:14:125:14 | access to local variable a : Int32[] [element] : Int32 | +| J.cs:119:13:119:13 | [post] access to local variable a : Int32[] [element] : Int32 | J.cs:125:14:125:14 | access to local variable a : Int32[] [element] : Int32 | +| J.cs:119:20:119:34 | call to method Source : Int32 | J.cs:119:13:119:13 | [post] access to local variable a : Int32[] [element] : Int32 | | J.cs:119:20:119:34 | call to method Source : Int32 | J.cs:119:13:119:13 | [post] access to local variable a : Int32[] [element] : Int32 | | J.cs:125:14:125:14 | access to local variable a : Int32[] [element] : Int32 | J.cs:125:14:125:17 | access to array element : Int32 | +| J.cs:125:14:125:14 | access to local variable a : Int32[] [element] : Int32 | J.cs:125:14:125:17 | access to array element : Int32 | +| J.cs:125:14:125:17 | access to array element : Int32 | J.cs:125:14:125:17 | (...) ... | | J.cs:125:14:125:17 | access to array element : Int32 | J.cs:125:14:125:17 | (...) ... | nodes | A.cs:5:17:5:28 | call to method Source : C | semmle.label | call to method Source : C | +| A.cs:5:17:5:28 | call to method Source : C | semmle.label | call to method Source : C | +| A.cs:6:17:6:25 | call to method Make : B [field c] : C | semmle.label | call to method Make : B [field c] : C | | A.cs:6:17:6:25 | call to method Make : B [field c] : C | semmle.label | call to method Make : B [field c] : C | | A.cs:6:24:6:24 | access to local variable c : C | semmle.label | access to local variable c : C | +| A.cs:6:24:6:24 | access to local variable c : C | semmle.label | access to local variable c : C | +| A.cs:7:14:7:14 | access to local variable b : B [field c] : C | semmle.label | access to local variable b : B [field c] : C | | A.cs:7:14:7:14 | access to local variable b : B [field c] : C | semmle.label | access to local variable b : B [field c] : C | | A.cs:7:14:7:16 | access to field c | semmle.label | access to field c | +| A.cs:7:14:7:16 | access to field c | semmle.label | access to field c | +| A.cs:13:9:13:9 | [post] access to local variable b : B [field c] : C1 | semmle.label | [post] access to local variable b : B [field c] : C1 | | A.cs:13:9:13:9 | [post] access to local variable b : B [field c] : C1 | semmle.label | [post] access to local variable b : B [field c] : C1 | | A.cs:13:15:13:29 | call to method Source : C1 | semmle.label | call to method Source : C1 | +| A.cs:13:15:13:29 | call to method Source : C1 | semmle.label | call to method Source : C1 | +| A.cs:14:14:14:14 | access to local variable b : B [field c] : C1 | semmle.label | access to local variable b : B [field c] : C1 | | A.cs:14:14:14:14 | access to local variable b : B [field c] : C1 | semmle.label | access to local variable b : B [field c] : C1 | | A.cs:14:14:14:20 | call to method Get | semmle.label | call to method Get | +| A.cs:14:14:14:20 | call to method Get | semmle.label | call to method Get | +| A.cs:15:14:15:42 | call to method Get | semmle.label | call to method Get | | A.cs:15:14:15:42 | call to method Get | semmle.label | call to method Get | | A.cs:15:15:15:35 | object creation of type B : B [field c] : C | semmle.label | object creation of type B : B [field c] : C | +| A.cs:15:15:15:35 | object creation of type B : B [field c] : C | semmle.label | object creation of type B : B [field c] : C | +| A.cs:15:21:15:34 | call to method Source : C | semmle.label | call to method Source : C | | A.cs:15:21:15:34 | call to method Source : C | semmle.label | call to method Source : C | | A.cs:22:14:22:38 | call to method SetOnB : B [field c] : C2 | semmle.label | call to method SetOnB : B [field c] : C2 | +| A.cs:22:14:22:38 | call to method SetOnB : B [field c] : C2 | semmle.label | call to method SetOnB : B [field c] : C2 | +| A.cs:22:25:22:37 | call to method Source : C2 | semmle.label | call to method Source : C2 | | A.cs:22:25:22:37 | call to method Source : C2 | semmle.label | call to method Source : C2 | | A.cs:24:14:24:15 | access to local variable b2 : B [field c] : C2 | semmle.label | access to local variable b2 : B [field c] : C2 | +| A.cs:24:14:24:15 | access to local variable b2 : B [field c] : C2 | semmle.label | access to local variable b2 : B [field c] : C2 | +| A.cs:24:14:24:17 | access to field c | semmle.label | access to field c | | A.cs:24:14:24:17 | access to field c | semmle.label | access to field c | | A.cs:31:14:31:42 | call to method SetOnBWrap : B [field c] : C2 | semmle.label | call to method SetOnBWrap : B [field c] : C2 | +| A.cs:31:14:31:42 | call to method SetOnBWrap : B [field c] : C2 | semmle.label | call to method SetOnBWrap : B [field c] : C2 | +| A.cs:31:29:31:41 | call to method Source : C2 | semmle.label | call to method Source : C2 | | A.cs:31:29:31:41 | call to method Source : C2 | semmle.label | call to method Source : C2 | | A.cs:33:14:33:15 | access to local variable b2 : B [field c] : C2 | semmle.label | access to local variable b2 : B [field c] : C2 | +| A.cs:33:14:33:15 | access to local variable b2 : B [field c] : C2 | semmle.label | access to local variable b2 : B [field c] : C2 | +| A.cs:33:14:33:17 | access to field c | semmle.label | access to field c | | A.cs:33:14:33:17 | access to field c | semmle.label | access to field c | | A.cs:36:33:36:33 | c : C2 | semmle.label | c : C2 | +| A.cs:36:33:36:33 | c : C2 | semmle.label | c : C2 | +| A.cs:38:18:38:30 | call to method SetOnB : B [field c] : C2 | semmle.label | call to method SetOnB : B [field c] : C2 | | A.cs:38:18:38:30 | call to method SetOnB : B [field c] : C2 | semmle.label | call to method SetOnB : B [field c] : C2 | | A.cs:38:29:38:29 | access to parameter c : C2 | semmle.label | access to parameter c : C2 | +| A.cs:38:29:38:29 | access to parameter c : C2 | semmle.label | access to parameter c : C2 | +| A.cs:39:16:39:28 | ... ? ... : ... : B [field c] : C2 | semmle.label | ... ? ... : ... : B [field c] : C2 | | A.cs:39:16:39:28 | ... ? ... : ... : B [field c] : C2 | semmle.label | ... ? ... : ... : B [field c] : C2 | | A.cs:42:29:42:29 | c : C2 | semmle.label | c : C2 | +| A.cs:42:29:42:29 | c : C2 | semmle.label | c : C2 | +| A.cs:47:13:47:14 | [post] access to local variable b2 : B [field c] : C2 | semmle.label | [post] access to local variable b2 : B [field c] : C2 | | A.cs:47:13:47:14 | [post] access to local variable b2 : B [field c] : C2 | semmle.label | [post] access to local variable b2 : B [field c] : C2 | | A.cs:47:20:47:20 | access to parameter c : C2 | semmle.label | access to parameter c : C2 | +| A.cs:47:20:47:20 | access to parameter c : C2 | semmle.label | access to parameter c : C2 | +| A.cs:48:20:48:21 | access to local variable b2 : B [field c] : C2 | semmle.label | access to local variable b2 : B [field c] : C2 | | A.cs:48:20:48:21 | access to local variable b2 : B [field c] : C2 | semmle.label | access to local variable b2 : B [field c] : C2 | | A.cs:55:17:55:28 | call to method Source : A | semmle.label | call to method Source : A | +| A.cs:55:17:55:28 | call to method Source : A | semmle.label | call to method Source : A | +| A.cs:57:9:57:10 | [post] access to local variable c1 : C1 [field a] : A | semmle.label | [post] access to local variable c1 : C1 [field a] : A | | A.cs:57:9:57:10 | [post] access to local variable c1 : C1 [field a] : A | semmle.label | [post] access to local variable c1 : C1 [field a] : A | | A.cs:57:16:57:16 | access to local variable a : A | semmle.label | access to local variable a : A | +| A.cs:57:16:57:16 | access to local variable a : A | semmle.label | access to local variable a : A | +| A.cs:58:12:58:13 | access to local variable c1 : C1 [field a] : A | semmle.label | access to local variable c1 : C1 [field a] : A | | A.cs:58:12:58:13 | access to local variable c1 : C1 [field a] : A | semmle.label | access to local variable c1 : C1 [field a] : A | | A.cs:60:22:60:22 | c : C1 [field a] : A | semmle.label | c : C1 [field a] : A | +| A.cs:60:22:60:22 | c : C1 [field a] : A | semmle.label | c : C1 [field a] : A | +| A.cs:64:18:64:26 | access to field a | semmle.label | access to field a | | A.cs:64:18:64:26 | access to field a | semmle.label | access to field a | | A.cs:64:19:64:23 | (...) ... : C1 [field a] : A | semmle.label | (...) ... : C1 [field a] : A | +| A.cs:64:19:64:23 | (...) ... : C1 [field a] : A | semmle.label | (...) ... : C1 [field a] : A | +| A.cs:83:9:83:9 | [post] access to parameter b : B [field c] : C | semmle.label | [post] access to parameter b : B [field c] : C | | A.cs:83:9:83:9 | [post] access to parameter b : B [field c] : C | semmle.label | [post] access to parameter b : B [field c] : C | | A.cs:83:15:83:26 | call to method Source : C | semmle.label | call to method Source : C | +| A.cs:83:15:83:26 | call to method Source : C | semmle.label | call to method Source : C | +| A.cs:88:12:88:12 | [post] access to local variable b : B [field c] : C | semmle.label | [post] access to local variable b : B [field c] : C | | A.cs:88:12:88:12 | [post] access to local variable b : B [field c] : C | semmle.label | [post] access to local variable b : B [field c] : C | | A.cs:89:14:89:14 | access to local variable b : B [field c] : C | semmle.label | access to local variable b : B [field c] : C | +| A.cs:89:14:89:14 | access to local variable b : B [field c] : C | semmle.label | access to local variable b : B [field c] : C | +| A.cs:89:14:89:16 | access to field c | semmle.label | access to field c | | A.cs:89:14:89:16 | access to field c | semmle.label | access to field c | | A.cs:95:20:95:20 | b : B | semmle.label | b : B | +| A.cs:95:20:95:20 | b : B | semmle.label | b : B | +| A.cs:97:13:97:13 | [post] access to parameter b : B [field c] : C | semmle.label | [post] access to parameter b : B [field c] : C | | A.cs:97:13:97:13 | [post] access to parameter b : B [field c] : C | semmle.label | [post] access to parameter b : B [field c] : C | | A.cs:97:13:97:13 | access to parameter b : B | semmle.label | access to parameter b : B | +| A.cs:97:13:97:13 | access to parameter b : B | semmle.label | access to parameter b : B | | A.cs:97:19:97:32 | call to method Source : C | semmle.label | call to method Source : C | +| A.cs:97:19:97:32 | call to method Source : C | semmle.label | call to method Source : C | +| A.cs:98:13:98:16 | [post] this access : D [field b, field c] : C | semmle.label | [post] this access : D [field b, field c] : C | | A.cs:98:13:98:16 | [post] this access : D [field b, field c] : C | semmle.label | [post] this access : D [field b, field c] : C | | A.cs:98:13:98:16 | [post] this access : D [field b] : B | semmle.label | [post] this access : D [field b] : B | | A.cs:98:13:98:16 | [post] this access : D [field b] : B | semmle.label | [post] this access : D [field b] : B | +| A.cs:98:13:98:16 | [post] this access : D [field b] : B | semmle.label | [post] this access : D [field b] : B | +| A.cs:98:13:98:16 | [post] this access : D [field b] : B | semmle.label | [post] this access : D [field b] : B | +| A.cs:98:22:98:43 | ... ? ... : ... : B | semmle.label | ... ? ... : ... : B | +| A.cs:98:22:98:43 | ... ? ... : ... : B | semmle.label | ... ? ... : ... : B | | A.cs:98:22:98:43 | ... ? ... : ... : B | semmle.label | ... ? ... : ... : B | | A.cs:98:22:98:43 | ... ? ... : ... : B | semmle.label | ... ? ... : ... : B | | A.cs:98:22:98:43 | ... ? ... : ... : B [field c] : C | semmle.label | ... ? ... : ... : B [field c] : C | +| A.cs:98:22:98:43 | ... ? ... : ... : B [field c] : C | semmle.label | ... ? ... : ... : B [field c] : C | +| A.cs:98:30:98:43 | call to method Source : B | semmle.label | call to method Source : B | | A.cs:98:30:98:43 | call to method Source : B | semmle.label | call to method Source : B | | A.cs:104:17:104:30 | call to method Source : B | semmle.label | call to method Source : B | +| A.cs:104:17:104:30 | call to method Source : B | semmle.label | call to method Source : B | +| A.cs:105:17:105:29 | object creation of type D : D [field b, field c] : C | semmle.label | object creation of type D : D [field b, field c] : C | | A.cs:105:17:105:29 | object creation of type D : D [field b, field c] : C | semmle.label | object creation of type D : D [field b, field c] : C | | A.cs:105:17:105:29 | object creation of type D : D [field b] : B | semmle.label | object creation of type D : D [field b] : B | +| A.cs:105:17:105:29 | object creation of type D : D [field b] : B | semmle.label | object creation of type D : D [field b] : B | +| A.cs:105:23:105:23 | [post] access to local variable b : B [field c] : C | semmle.label | [post] access to local variable b : B [field c] : C | | A.cs:105:23:105:23 | [post] access to local variable b : B [field c] : C | semmle.label | [post] access to local variable b : B [field c] : C | | A.cs:105:23:105:23 | access to local variable b : B | semmle.label | access to local variable b : B | +| A.cs:105:23:105:23 | access to local variable b : B | semmle.label | access to local variable b : B | +| A.cs:106:14:106:14 | access to local variable d : D [field b] : B | semmle.label | access to local variable d : D [field b] : B | | A.cs:106:14:106:14 | access to local variable d : D [field b] : B | semmle.label | access to local variable d : D [field b] : B | | A.cs:106:14:106:16 | access to field b | semmle.label | access to field b | +| A.cs:106:14:106:16 | access to field b | semmle.label | access to field b | +| A.cs:107:14:107:14 | access to local variable d : D [field b, field c] : C | semmle.label | access to local variable d : D [field b, field c] : C | | A.cs:107:14:107:14 | access to local variable d : D [field b, field c] : C | semmle.label | access to local variable d : D [field b, field c] : C | | A.cs:107:14:107:16 | access to field b : B [field c] : C | semmle.label | access to field b : B [field c] : C | +| A.cs:107:14:107:16 | access to field b : B [field c] : C | semmle.label | access to field b : B [field c] : C | +| A.cs:107:14:107:18 | access to field c | semmle.label | access to field c | | A.cs:107:14:107:18 | access to field c | semmle.label | access to field c | | A.cs:108:14:108:14 | access to local variable b : B [field c] : C | semmle.label | access to local variable b : B [field c] : C | +| A.cs:108:14:108:14 | access to local variable b : B [field c] : C | semmle.label | access to local variable b : B [field c] : C | +| A.cs:108:14:108:16 | access to field c | semmle.label | access to field c | | A.cs:108:14:108:16 | access to field c | semmle.label | access to field c | | A.cs:113:17:113:29 | call to method Source : B | semmle.label | call to method Source : B | +| A.cs:113:17:113:29 | call to method Source : B | semmle.label | call to method Source : B | +| A.cs:114:18:114:54 | object creation of type MyList : MyList [field head] : B | semmle.label | object creation of type MyList : MyList [field head] : B | | A.cs:114:18:114:54 | object creation of type MyList : MyList [field head] : B | semmle.label | object creation of type MyList : MyList [field head] : B | | A.cs:114:29:114:29 | access to local variable b : B | semmle.label | access to local variable b : B | +| A.cs:114:29:114:29 | access to local variable b : B | semmle.label | access to local variable b : B | +| A.cs:115:18:115:37 | object creation of type MyList : MyList [field next, field head] : B | semmle.label | object creation of type MyList : MyList [field next, field head] : B | | A.cs:115:18:115:37 | object creation of type MyList : MyList [field next, field head] : B | semmle.label | object creation of type MyList : MyList [field next, field head] : B | | A.cs:115:35:115:36 | access to local variable l1 : MyList [field head] : B | semmle.label | access to local variable l1 : MyList [field head] : B | +| A.cs:115:35:115:36 | access to local variable l1 : MyList [field head] : B | semmle.label | access to local variable l1 : MyList [field head] : B | +| A.cs:116:18:116:37 | object creation of type MyList : MyList [field next, field next, field head] : B | semmle.label | object creation of type MyList : MyList [field next, field next, field head] : B | | A.cs:116:18:116:37 | object creation of type MyList : MyList [field next, field next, field head] : B | semmle.label | object creation of type MyList : MyList [field next, field next, field head] : B | | A.cs:116:35:116:36 | access to local variable l2 : MyList [field next, field head] : B | semmle.label | access to local variable l2 : MyList [field next, field head] : B | +| A.cs:116:35:116:36 | access to local variable l2 : MyList [field next, field head] : B | semmle.label | access to local variable l2 : MyList [field next, field head] : B | +| A.cs:119:14:119:15 | access to local variable l3 : MyList [field next, field next, field head] : B | semmle.label | access to local variable l3 : MyList [field next, field next, field head] : B | | A.cs:119:14:119:15 | access to local variable l3 : MyList [field next, field next, field head] : B | semmle.label | access to local variable l3 : MyList [field next, field next, field head] : B | | A.cs:119:14:119:20 | access to field next : MyList [field next, field head] : B | semmle.label | access to field next : MyList [field next, field head] : B | +| A.cs:119:14:119:20 | access to field next : MyList [field next, field head] : B | semmle.label | access to field next : MyList [field next, field head] : B | +| A.cs:119:14:119:25 | access to field next : MyList [field head] : B | semmle.label | access to field next : MyList [field head] : B | | A.cs:119:14:119:25 | access to field next : MyList [field head] : B | semmle.label | access to field next : MyList [field head] : B | | A.cs:119:14:119:30 | access to field head | semmle.label | access to field head | +| A.cs:119:14:119:30 | access to field head | semmle.label | access to field head | +| A.cs:121:41:121:41 | access to local variable l : MyList [field next, field head] : B | semmle.label | access to local variable l : MyList [field next, field head] : B | | A.cs:121:41:121:41 | access to local variable l : MyList [field next, field head] : B | semmle.label | access to local variable l : MyList [field next, field head] : B | | A.cs:121:41:121:41 | access to local variable l : MyList [field next, field next, field head] : B | semmle.label | access to local variable l : MyList [field next, field next, field head] : B | +| A.cs:121:41:121:41 | access to local variable l : MyList [field next, field next, field head] : B | semmle.label | access to local variable l : MyList [field next, field next, field head] : B | +| A.cs:121:41:121:46 | access to field next : MyList [field head] : B | semmle.label | access to field next : MyList [field head] : B | | A.cs:121:41:121:46 | access to field next : MyList [field head] : B | semmle.label | access to field next : MyList [field head] : B | | A.cs:121:41:121:46 | access to field next : MyList [field next, field head] : B | semmle.label | access to field next : MyList [field next, field head] : B | +| A.cs:121:41:121:46 | access to field next : MyList [field next, field head] : B | semmle.label | access to field next : MyList [field next, field head] : B | +| A.cs:123:18:123:18 | access to local variable l : MyList [field head] : B | semmle.label | access to local variable l : MyList [field head] : B | | A.cs:123:18:123:18 | access to local variable l : MyList [field head] : B | semmle.label | access to local variable l : MyList [field head] : B | | A.cs:123:18:123:23 | access to field head | semmle.label | access to field head | +| A.cs:123:18:123:23 | access to field head | semmle.label | access to field head | +| A.cs:141:20:141:20 | c : C | semmle.label | c : C | | A.cs:141:20:141:20 | c : C | semmle.label | c : C | | A.cs:143:13:143:16 | [post] this access : B [field c] : C | semmle.label | [post] this access : B [field c] : C | +| A.cs:143:13:143:16 | [post] this access : B [field c] : C | semmle.label | [post] this access : B [field c] : C | +| A.cs:143:22:143:22 | access to parameter c : C | semmle.label | access to parameter c : C | | A.cs:143:22:143:22 | access to parameter c : C | semmle.label | access to parameter c : C | | A.cs:145:27:145:27 | c : C | semmle.label | c : C | +| A.cs:145:27:145:27 | c : C | semmle.label | c : C | +| A.cs:145:27:145:27 | c : C1 | semmle.label | c : C1 | | A.cs:145:27:145:27 | c : C1 | semmle.label | c : C1 | | A.cs:145:27:145:27 | c : C2 | semmle.label | c : C2 | +| A.cs:145:27:145:27 | c : C2 | semmle.label | c : C2 | +| A.cs:145:32:145:35 | [post] this access : B [field c] : C | semmle.label | [post] this access : B [field c] : C | | A.cs:145:32:145:35 | [post] this access : B [field c] : C | semmle.label | [post] this access : B [field c] : C | | A.cs:145:32:145:35 | [post] this access : B [field c] : C1 | semmle.label | [post] this access : B [field c] : C1 | +| A.cs:145:32:145:35 | [post] this access : B [field c] : C1 | semmle.label | [post] this access : B [field c] : C1 | +| A.cs:145:32:145:35 | [post] this access : B [field c] : C2 | semmle.label | [post] this access : B [field c] : C2 | | A.cs:145:32:145:35 | [post] this access : B [field c] : C2 | semmle.label | [post] this access : B [field c] : C2 | | A.cs:145:41:145:41 | access to parameter c : C | semmle.label | access to parameter c : C | +| A.cs:145:41:145:41 | access to parameter c : C | semmle.label | access to parameter c : C | +| A.cs:145:41:145:41 | access to parameter c : C1 | semmle.label | access to parameter c : C1 | | A.cs:145:41:145:41 | access to parameter c : C1 | semmle.label | access to parameter c : C1 | | A.cs:145:41:145:41 | access to parameter c : C2 | semmle.label | access to parameter c : C2 | +| A.cs:145:41:145:41 | access to parameter c : C2 | semmle.label | access to parameter c : C2 | +| A.cs:146:18:146:20 | this : B [field c] : C | semmle.label | this : B [field c] : C | | A.cs:146:18:146:20 | this : B [field c] : C | semmle.label | this : B [field c] : C | | A.cs:146:18:146:20 | this : B [field c] : C1 | semmle.label | this : B [field c] : C1 | +| A.cs:146:18:146:20 | this : B [field c] : C1 | semmle.label | this : B [field c] : C1 | +| A.cs:146:33:146:36 | this access : B [field c] : C | semmle.label | this access : B [field c] : C | | A.cs:146:33:146:36 | this access : B [field c] : C | semmle.label | this access : B [field c] : C | | A.cs:146:33:146:36 | this access : B [field c] : C1 | semmle.label | this access : B [field c] : C1 | +| A.cs:146:33:146:36 | this access : B [field c] : C1 | semmle.label | this access : B [field c] : C1 | +| A.cs:146:33:146:38 | access to field c : C | semmle.label | access to field c : C | | A.cs:146:33:146:38 | access to field c : C | semmle.label | access to field c : C | | A.cs:146:33:146:38 | access to field c : C1 | semmle.label | access to field c : C1 | +| A.cs:146:33:146:38 | access to field c : C1 | semmle.label | access to field c : C1 | +| A.cs:147:32:147:32 | c : C | semmle.label | c : C | | A.cs:147:32:147:32 | c : C | semmle.label | c : C | | A.cs:149:20:149:27 | object creation of type B : B [field c] : C | semmle.label | object creation of type B : B [field c] : C | +| A.cs:149:20:149:27 | object creation of type B : B [field c] : C | semmle.label | object creation of type B : B [field c] : C | +| A.cs:149:26:149:26 | access to parameter c : C | semmle.label | access to parameter c : C | | A.cs:149:26:149:26 | access to parameter c : C | semmle.label | access to parameter c : C | | A.cs:157:25:157:28 | head : B | semmle.label | head : B | +| A.cs:157:25:157:28 | head : B | semmle.label | head : B | +| A.cs:157:38:157:41 | next : MyList [field head] : B | semmle.label | next : MyList [field head] : B | | A.cs:157:38:157:41 | next : MyList [field head] : B | semmle.label | next : MyList [field head] : B | | A.cs:157:38:157:41 | next : MyList [field next, field head] : B | semmle.label | next : MyList [field next, field head] : B | +| A.cs:157:38:157:41 | next : MyList [field next, field head] : B | semmle.label | next : MyList [field next, field head] : B | +| A.cs:159:13:159:16 | [post] this access : MyList [field head] : B | semmle.label | [post] this access : MyList [field head] : B | | A.cs:159:13:159:16 | [post] this access : MyList [field head] : B | semmle.label | [post] this access : MyList [field head] : B | | A.cs:159:25:159:28 | access to parameter head : B | semmle.label | access to parameter head : B | +| A.cs:159:25:159:28 | access to parameter head : B | semmle.label | access to parameter head : B | +| A.cs:160:13:160:16 | [post] this access : MyList [field next, field head] : B | semmle.label | [post] this access : MyList [field next, field head] : B | | A.cs:160:13:160:16 | [post] this access : MyList [field next, field head] : B | semmle.label | [post] this access : MyList [field next, field head] : B | | A.cs:160:13:160:16 | [post] this access : MyList [field next, field next, field head] : B | semmle.label | [post] this access : MyList [field next, field next, field head] : B | +| A.cs:160:13:160:16 | [post] this access : MyList [field next, field next, field head] : B | semmle.label | [post] this access : MyList [field next, field next, field head] : B | +| A.cs:160:25:160:28 | access to parameter next : MyList [field head] : B | semmle.label | access to parameter next : MyList [field head] : B | | A.cs:160:25:160:28 | access to parameter next : MyList [field head] : B | semmle.label | access to parameter next : MyList [field head] : B | | A.cs:160:25:160:28 | access to parameter next : MyList [field next, field head] : B | semmle.label | access to parameter next : MyList [field next, field head] : B | +| A.cs:160:25:160:28 | access to parameter next : MyList [field next, field head] : B | semmle.label | access to parameter next : MyList [field next, field head] : B | +| B.cs:5:17:5:31 | call to method Source : Elem | semmle.label | call to method Source : Elem | | B.cs:5:17:5:31 | call to method Source : Elem | semmle.label | call to method Source : Elem | | B.cs:6:18:6:34 | object creation of type Box1 : Box1 [field elem1] : Elem | semmle.label | object creation of type Box1 : Box1 [field elem1] : Elem | +| B.cs:6:18:6:34 | object creation of type Box1 : Box1 [field elem1] : Elem | semmle.label | object creation of type Box1 : Box1 [field elem1] : Elem | +| B.cs:6:27:6:27 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | | B.cs:6:27:6:27 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | | B.cs:7:18:7:29 | object creation of type Box2 : Box2 [field box1, field elem1] : Elem | semmle.label | object creation of type Box2 : Box2 [field box1, field elem1] : Elem | +| B.cs:7:18:7:29 | object creation of type Box2 : Box2 [field box1, field elem1] : Elem | semmle.label | object creation of type Box2 : Box2 [field box1, field elem1] : Elem | +| B.cs:7:27:7:28 | access to local variable b1 : Box1 [field elem1] : Elem | semmle.label | access to local variable b1 : Box1 [field elem1] : Elem | | B.cs:7:27:7:28 | access to local variable b1 : Box1 [field elem1] : Elem | semmle.label | access to local variable b1 : Box1 [field elem1] : Elem | | B.cs:8:14:8:15 | access to local variable b2 : Box2 [field box1, field elem1] : Elem | semmle.label | access to local variable b2 : Box2 [field box1, field elem1] : Elem | +| B.cs:8:14:8:15 | access to local variable b2 : Box2 [field box1, field elem1] : Elem | semmle.label | access to local variable b2 : Box2 [field box1, field elem1] : Elem | +| B.cs:8:14:8:20 | access to field box1 : Box1 [field elem1] : Elem | semmle.label | access to field box1 : Box1 [field elem1] : Elem | | B.cs:8:14:8:20 | access to field box1 : Box1 [field elem1] : Elem | semmle.label | access to field box1 : Box1 [field elem1] : Elem | | B.cs:8:14:8:26 | access to field elem1 | semmle.label | access to field elem1 | +| B.cs:8:14:8:26 | access to field elem1 | semmle.label | access to field elem1 | +| B.cs:14:17:14:31 | call to method Source : Elem | semmle.label | call to method Source : Elem | | B.cs:14:17:14:31 | call to method Source : Elem | semmle.label | call to method Source : Elem | | B.cs:15:18:15:34 | object creation of type Box1 : Box1 [field elem2] : Elem | semmle.label | object creation of type Box1 : Box1 [field elem2] : Elem | +| B.cs:15:18:15:34 | object creation of type Box1 : Box1 [field elem2] : Elem | semmle.label | object creation of type Box1 : Box1 [field elem2] : Elem | +| B.cs:15:33:15:33 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | | B.cs:15:33:15:33 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | | B.cs:16:18:16:29 | object creation of type Box2 : Box2 [field box1, field elem2] : Elem | semmle.label | object creation of type Box2 : Box2 [field box1, field elem2] : Elem | +| B.cs:16:18:16:29 | object creation of type Box2 : Box2 [field box1, field elem2] : Elem | semmle.label | object creation of type Box2 : Box2 [field box1, field elem2] : Elem | +| B.cs:16:27:16:28 | access to local variable b1 : Box1 [field elem2] : Elem | semmle.label | access to local variable b1 : Box1 [field elem2] : Elem | | B.cs:16:27:16:28 | access to local variable b1 : Box1 [field elem2] : Elem | semmle.label | access to local variable b1 : Box1 [field elem2] : Elem | | B.cs:18:14:18:15 | access to local variable b2 : Box2 [field box1, field elem2] : Elem | semmle.label | access to local variable b2 : Box2 [field box1, field elem2] : Elem | +| B.cs:18:14:18:15 | access to local variable b2 : Box2 [field box1, field elem2] : Elem | semmle.label | access to local variable b2 : Box2 [field box1, field elem2] : Elem | +| B.cs:18:14:18:20 | access to field box1 : Box1 [field elem2] : Elem | semmle.label | access to field box1 : Box1 [field elem2] : Elem | | B.cs:18:14:18:20 | access to field box1 : Box1 [field elem2] : Elem | semmle.label | access to field box1 : Box1 [field elem2] : Elem | | B.cs:18:14:18:26 | access to field elem2 | semmle.label | access to field elem2 | +| B.cs:18:14:18:26 | access to field elem2 | semmle.label | access to field elem2 | +| B.cs:29:26:29:27 | e1 : Elem | semmle.label | e1 : Elem | | B.cs:29:26:29:27 | e1 : Elem | semmle.label | e1 : Elem | | B.cs:29:35:29:36 | e2 : Elem | semmle.label | e2 : Elem | +| B.cs:29:35:29:36 | e2 : Elem | semmle.label | e2 : Elem | +| B.cs:31:13:31:16 | [post] this access : Box1 [field elem1] : Elem | semmle.label | [post] this access : Box1 [field elem1] : Elem | | B.cs:31:13:31:16 | [post] this access : Box1 [field elem1] : Elem | semmle.label | [post] this access : Box1 [field elem1] : Elem | | B.cs:31:26:31:27 | access to parameter e1 : Elem | semmle.label | access to parameter e1 : Elem | +| B.cs:31:26:31:27 | access to parameter e1 : Elem | semmle.label | access to parameter e1 : Elem | +| B.cs:32:13:32:16 | [post] this access : Box1 [field elem2] : Elem | semmle.label | [post] this access : Box1 [field elem2] : Elem | | B.cs:32:13:32:16 | [post] this access : Box1 [field elem2] : Elem | semmle.label | [post] this access : Box1 [field elem2] : Elem | | B.cs:32:26:32:27 | access to parameter e2 : Elem | semmle.label | access to parameter e2 : Elem | +| B.cs:32:26:32:27 | access to parameter e2 : Elem | semmle.label | access to parameter e2 : Elem | +| B.cs:39:26:39:27 | b1 : Box1 [field elem1] : Elem | semmle.label | b1 : Box1 [field elem1] : Elem | | B.cs:39:26:39:27 | b1 : Box1 [field elem1] : Elem | semmle.label | b1 : Box1 [field elem1] : Elem | | B.cs:39:26:39:27 | b1 : Box1 [field elem2] : Elem | semmle.label | b1 : Box1 [field elem2] : Elem | +| B.cs:39:26:39:27 | b1 : Box1 [field elem2] : Elem | semmle.label | b1 : Box1 [field elem2] : Elem | +| B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem1] : Elem | semmle.label | [post] this access : Box2 [field box1, field elem1] : Elem | | B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem1] : Elem | semmle.label | [post] this access : Box2 [field box1, field elem1] : Elem | | B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem2] : Elem | semmle.label | [post] this access : Box2 [field box1, field elem2] : Elem | +| B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem2] : Elem | semmle.label | [post] this access : Box2 [field box1, field elem2] : Elem | +| B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem1] : Elem | semmle.label | access to parameter b1 : Box1 [field elem1] : Elem | | B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem1] : Elem | semmle.label | access to parameter b1 : Box1 [field elem1] : Elem | | B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem2] : Elem | semmle.label | access to parameter b1 : Box1 [field elem2] : Elem | +| B.cs:41:25:41:26 | access to parameter b1 : Box1 [field elem2] : Elem | semmle.label | access to parameter b1 : Box1 [field elem2] : Elem | +| C.cs:3:18:3:19 | [post] this access : C [field s1] : Elem | semmle.label | [post] this access : C [field s1] : Elem | | C.cs:3:18:3:19 | [post] this access : C [field s1] : Elem | semmle.label | [post] this access : C [field s1] : Elem | | C.cs:3:23:3:37 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| C.cs:3:23:3:37 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| C.cs:4:27:4:28 | [post] this access : C [field s2] : Elem | semmle.label | [post] this access : C [field s2] : Elem | | C.cs:4:27:4:28 | [post] this access : C [field s2] : Elem | semmle.label | [post] this access : C [field s2] : Elem | | C.cs:4:32:4:46 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| C.cs:4:32:4:46 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| C.cs:6:30:6:44 | call to method Source : Elem | semmle.label | call to method Source : Elem | | C.cs:6:30:6:44 | call to method Source : Elem | semmle.label | call to method Source : Elem | | C.cs:7:18:7:19 | [post] this access : C [property s5] : Elem | semmle.label | [post] this access : C [property s5] : Elem | +| C.cs:7:18:7:19 | [post] this access : C [property s5] : Elem | semmle.label | [post] this access : C [property s5] : Elem | +| C.cs:7:37:7:51 | call to method Source : Elem | semmle.label | call to method Source : Elem | | C.cs:7:37:7:51 | call to method Source : Elem | semmle.label | call to method Source : Elem | | C.cs:8:30:8:44 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| C.cs:8:30:8:44 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| C.cs:12:15:12:21 | object creation of type C : C [field s1] : Elem | semmle.label | object creation of type C : C [field s1] : Elem | | C.cs:12:15:12:21 | object creation of type C : C [field s1] : Elem | semmle.label | object creation of type C : C [field s1] : Elem | | C.cs:12:15:12:21 | object creation of type C : C [field s2] : Elem | semmle.label | object creation of type C : C [field s2] : Elem | +| C.cs:12:15:12:21 | object creation of type C : C [field s2] : Elem | semmle.label | object creation of type C : C [field s2] : Elem | +| C.cs:12:15:12:21 | object creation of type C : C [field s3] : Elem | semmle.label | object creation of type C : C [field s3] : Elem | | C.cs:12:15:12:21 | object creation of type C : C [field s3] : Elem | semmle.label | object creation of type C : C [field s3] : Elem | | C.cs:12:15:12:21 | object creation of type C : C [property s5] : Elem | semmle.label | object creation of type C : C [property s5] : Elem | +| C.cs:12:15:12:21 | object creation of type C : C [property s5] : Elem | semmle.label | object creation of type C : C [property s5] : Elem | +| C.cs:13:9:13:9 | access to local variable c : C [field s1] : Elem | semmle.label | access to local variable c : C [field s1] : Elem | | C.cs:13:9:13:9 | access to local variable c : C [field s1] : Elem | semmle.label | access to local variable c : C [field s1] : Elem | | C.cs:13:9:13:9 | access to local variable c : C [field s2] : Elem | semmle.label | access to local variable c : C [field s2] : Elem | +| C.cs:13:9:13:9 | access to local variable c : C [field s2] : Elem | semmle.label | access to local variable c : C [field s2] : Elem | +| C.cs:13:9:13:9 | access to local variable c : C [field s3] : Elem | semmle.label | access to local variable c : C [field s3] : Elem | | C.cs:13:9:13:9 | access to local variable c : C [field s3] : Elem | semmle.label | access to local variable c : C [field s3] : Elem | | C.cs:13:9:13:9 | access to local variable c : C [property s5] : Elem | semmle.label | access to local variable c : C [property s5] : Elem | +| C.cs:13:9:13:9 | access to local variable c : C [property s5] : Elem | semmle.label | access to local variable c : C [property s5] : Elem | +| C.cs:18:9:18:12 | [post] this access : C [field s3] : Elem | semmle.label | [post] this access : C [field s3] : Elem | | C.cs:18:9:18:12 | [post] this access : C [field s3] : Elem | semmle.label | [post] this access : C [field s3] : Elem | | C.cs:18:19:18:33 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| C.cs:18:19:18:33 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| C.cs:21:17:21:18 | this : C [field s1] : Elem | semmle.label | this : C [field s1] : Elem | | C.cs:21:17:21:18 | this : C [field s1] : Elem | semmle.label | this : C [field s1] : Elem | | C.cs:21:17:21:18 | this : C [field s2] : Elem | semmle.label | this : C [field s2] : Elem | +| C.cs:21:17:21:18 | this : C [field s2] : Elem | semmle.label | this : C [field s2] : Elem | +| C.cs:21:17:21:18 | this : C [field s3] : Elem | semmle.label | this : C [field s3] : Elem | | C.cs:21:17:21:18 | this : C [field s3] : Elem | semmle.label | this : C [field s3] : Elem | | C.cs:21:17:21:18 | this : C [property s5] : Elem | semmle.label | this : C [property s5] : Elem | +| C.cs:21:17:21:18 | this : C [property s5] : Elem | semmle.label | this : C [property s5] : Elem | +| C.cs:23:14:23:15 | access to field s1 | semmle.label | access to field s1 | | C.cs:23:14:23:15 | access to field s1 | semmle.label | access to field s1 | | C.cs:23:14:23:15 | this access : C [field s1] : Elem | semmle.label | this access : C [field s1] : Elem | +| C.cs:23:14:23:15 | this access : C [field s1] : Elem | semmle.label | this access : C [field s1] : Elem | +| C.cs:24:14:24:15 | access to field s2 | semmle.label | access to field s2 | | C.cs:24:14:24:15 | access to field s2 | semmle.label | access to field s2 | | C.cs:24:14:24:15 | this access : C [field s2] : Elem | semmle.label | this access : C [field s2] : Elem | +| C.cs:24:14:24:15 | this access : C [field s2] : Elem | semmle.label | this access : C [field s2] : Elem | +| C.cs:25:14:25:15 | access to field s3 | semmle.label | access to field s3 | | C.cs:25:14:25:15 | access to field s3 | semmle.label | access to field s3 | | C.cs:25:14:25:15 | this access : C [field s3] : Elem | semmle.label | this access : C [field s3] : Elem | +| C.cs:25:14:25:15 | this access : C [field s3] : Elem | semmle.label | this access : C [field s3] : Elem | +| C.cs:26:14:26:15 | access to field s4 | semmle.label | access to field s4 | | C.cs:26:14:26:15 | access to field s4 | semmle.label | access to field s4 | | C.cs:27:14:27:15 | access to property s5 | semmle.label | access to property s5 | +| C.cs:27:14:27:15 | access to property s5 | semmle.label | access to property s5 | +| C.cs:27:14:27:15 | this access : C [property s5] : Elem | semmle.label | this access : C [property s5] : Elem | | C.cs:27:14:27:15 | this access : C [property s5] : Elem | semmle.label | this access : C [property s5] : Elem | | C.cs:28:14:28:15 | access to property s6 | semmle.label | access to property s6 | +| C.cs:28:14:28:15 | access to property s6 | semmle.label | access to property s6 | +| C_ctor.cs:3:18:3:19 | [post] this access : C_no_ctor [field s1] : Elem | semmle.label | [post] this access : C_no_ctor [field s1] : Elem | | C_ctor.cs:3:18:3:19 | [post] this access : C_no_ctor [field s1] : Elem | semmle.label | [post] this access : C_no_ctor [field s1] : Elem | | C_ctor.cs:3:23:3:42 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| C_ctor.cs:3:23:3:42 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| C_ctor.cs:7:23:7:37 | object creation of type C_no_ctor : C_no_ctor [field s1] : Elem | semmle.label | object creation of type C_no_ctor : C_no_ctor [field s1] : Elem | | C_ctor.cs:7:23:7:37 | object creation of type C_no_ctor : C_no_ctor [field s1] : Elem | semmle.label | object creation of type C_no_ctor : C_no_ctor [field s1] : Elem | | C_ctor.cs:8:9:8:9 | access to local variable c : C_no_ctor [field s1] : Elem | semmle.label | access to local variable c : C_no_ctor [field s1] : Elem | +| C_ctor.cs:8:9:8:9 | access to local variable c : C_no_ctor [field s1] : Elem | semmle.label | access to local variable c : C_no_ctor [field s1] : Elem | +| C_ctor.cs:11:17:11:18 | this : C_no_ctor [field s1] : Elem | semmle.label | this : C_no_ctor [field s1] : Elem | | C_ctor.cs:11:17:11:18 | this : C_no_ctor [field s1] : Elem | semmle.label | this : C_no_ctor [field s1] : Elem | | C_ctor.cs:13:19:13:20 | access to field s1 | semmle.label | access to field s1 | +| C_ctor.cs:13:19:13:20 | access to field s1 | semmle.label | access to field s1 | +| C_ctor.cs:13:19:13:20 | this access : C_no_ctor [field s1] : Elem | semmle.label | this access : C_no_ctor [field s1] : Elem | | C_ctor.cs:13:19:13:20 | this access : C_no_ctor [field s1] : Elem | semmle.label | this access : C_no_ctor [field s1] : Elem | | C_ctor.cs:19:18:19:19 | [post] this access : C_with_ctor [field s1] : Elem | semmle.label | [post] this access : C_with_ctor [field s1] : Elem | +| C_ctor.cs:19:18:19:19 | [post] this access : C_with_ctor [field s1] : Elem | semmle.label | [post] this access : C_with_ctor [field s1] : Elem | +| C_ctor.cs:19:23:19:42 | call to method Source : Elem | semmle.label | call to method Source : Elem | | C_ctor.cs:19:23:19:42 | call to method Source : Elem | semmle.label | call to method Source : Elem | | C_ctor.cs:23:25:23:41 | object creation of type C_with_ctor : C_with_ctor [field s1] : Elem | semmle.label | object creation of type C_with_ctor : C_with_ctor [field s1] : Elem | +| C_ctor.cs:23:25:23:41 | object creation of type C_with_ctor : C_with_ctor [field s1] : Elem | semmle.label | object creation of type C_with_ctor : C_with_ctor [field s1] : Elem | +| C_ctor.cs:24:9:24:9 | access to local variable c : C_with_ctor [field s1] : Elem | semmle.label | access to local variable c : C_with_ctor [field s1] : Elem | | C_ctor.cs:24:9:24:9 | access to local variable c : C_with_ctor [field s1] : Elem | semmle.label | access to local variable c : C_with_ctor [field s1] : Elem | | C_ctor.cs:29:17:29:18 | this : C_with_ctor [field s1] : Elem | semmle.label | this : C_with_ctor [field s1] : Elem | +| C_ctor.cs:29:17:29:18 | this : C_with_ctor [field s1] : Elem | semmle.label | this : C_with_ctor [field s1] : Elem | +| C_ctor.cs:31:19:31:20 | access to field s1 | semmle.label | access to field s1 | | C_ctor.cs:31:19:31:20 | access to field s1 | semmle.label | access to field s1 | | C_ctor.cs:31:19:31:20 | this access : C_with_ctor [field s1] : Elem | semmle.label | this access : C_with_ctor [field s1] : Elem | +| C_ctor.cs:31:19:31:20 | this access : C_with_ctor [field s1] : Elem | semmle.label | this access : C_with_ctor [field s1] : Elem | +| D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | semmle.label | this : D [field trivialPropField] : Object | | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | semmle.label | this : D [field trivialPropField] : Object | | D.cs:8:22:8:25 | this access : D [field trivialPropField] : Object | semmle.label | this access : D [field trivialPropField] : Object | +| D.cs:8:22:8:25 | this access : D [field trivialPropField] : Object | semmle.label | this access : D [field trivialPropField] : Object | +| D.cs:8:22:8:42 | access to field trivialPropField : Object | semmle.label | access to field trivialPropField : Object | | D.cs:8:22:8:42 | access to field trivialPropField : Object | semmle.label | access to field trivialPropField : Object | | D.cs:9:9:9:11 | value : Object | semmle.label | value : Object | +| D.cs:9:9:9:11 | value : Object | semmle.label | value : Object | +| D.cs:9:15:9:18 | [post] this access : D [field trivialPropField] : Object | semmle.label | [post] this access : D [field trivialPropField] : Object | | D.cs:9:15:9:18 | [post] this access : D [field trivialPropField] : Object | semmle.label | [post] this access : D [field trivialPropField] : Object | | D.cs:9:39:9:43 | access to parameter value : Object | semmle.label | access to parameter value : Object | +| D.cs:9:39:9:43 | access to parameter value : Object | semmle.label | access to parameter value : Object | +| D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | semmle.label | this : D [field trivialPropField] : Object | | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | semmle.label | this : D [field trivialPropField] : Object | | D.cs:14:22:14:25 | this access : D [field trivialPropField] : Object | semmle.label | this access : D [field trivialPropField] : Object | +| D.cs:14:22:14:25 | this access : D [field trivialPropField] : Object | semmle.label | this access : D [field trivialPropField] : Object | +| D.cs:14:22:14:42 | access to field trivialPropField : Object | semmle.label | access to field trivialPropField : Object | | D.cs:14:22:14:42 | access to field trivialPropField : Object | semmle.label | access to field trivialPropField : Object | | D.cs:15:9:15:11 | value : Object | semmle.label | value : Object | +| D.cs:15:9:15:11 | value : Object | semmle.label | value : Object | +| D.cs:15:15:15:18 | [post] this access : D [field trivialPropField] : Object | semmle.label | [post] this access : D [field trivialPropField] : Object | | D.cs:15:15:15:18 | [post] this access : D [field trivialPropField] : Object | semmle.label | [post] this access : D [field trivialPropField] : Object | | D.cs:15:34:15:38 | access to parameter value : Object | semmle.label | access to parameter value : Object | +| D.cs:15:34:15:38 | access to parameter value : Object | semmle.label | access to parameter value : Object | +| D.cs:18:28:18:29 | o1 : Object | semmle.label | o1 : Object | | D.cs:18:28:18:29 | o1 : Object | semmle.label | o1 : Object | | D.cs:18:39:18:40 | o2 : Object | semmle.label | o2 : Object | +| D.cs:18:39:18:40 | o2 : Object | semmle.label | o2 : Object | +| D.cs:18:50:18:51 | o3 : Object | semmle.label | o3 : Object | | D.cs:18:50:18:51 | o3 : Object | semmle.label | o3 : Object | | D.cs:21:9:21:11 | [post] access to local variable ret : D [property AutoProp] : Object | semmle.label | [post] access to local variable ret : D [property AutoProp] : Object | +| D.cs:21:9:21:11 | [post] access to local variable ret : D [property AutoProp] : Object | semmle.label | [post] access to local variable ret : D [property AutoProp] : Object | +| D.cs:21:24:21:25 | access to parameter o1 : Object | semmle.label | access to parameter o1 : Object | | D.cs:21:24:21:25 | access to parameter o1 : Object | semmle.label | access to parameter o1 : Object | | D.cs:22:9:22:11 | [post] access to local variable ret : D [field trivialPropField] : Object | semmle.label | [post] access to local variable ret : D [field trivialPropField] : Object | +| D.cs:22:9:22:11 | [post] access to local variable ret : D [field trivialPropField] : Object | semmle.label | [post] access to local variable ret : D [field trivialPropField] : Object | +| D.cs:22:27:22:28 | access to parameter o2 : Object | semmle.label | access to parameter o2 : Object | | D.cs:22:27:22:28 | access to parameter o2 : Object | semmle.label | access to parameter o2 : Object | | D.cs:23:9:23:11 | [post] access to local variable ret : D [field trivialPropField] : Object | semmle.label | [post] access to local variable ret : D [field trivialPropField] : Object | +| D.cs:23:9:23:11 | [post] access to local variable ret : D [field trivialPropField] : Object | semmle.label | [post] access to local variable ret : D [field trivialPropField] : Object | +| D.cs:23:27:23:28 | access to parameter o3 : Object | semmle.label | access to parameter o3 : Object | | D.cs:23:27:23:28 | access to parameter o3 : Object | semmle.label | access to parameter o3 : Object | | D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | semmle.label | access to local variable ret : D [field trivialPropField] : Object | | D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | semmle.label | access to local variable ret : D [field trivialPropField] : Object | +| D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | semmle.label | access to local variable ret : D [field trivialPropField] : Object | +| D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | semmle.label | access to local variable ret : D [field trivialPropField] : Object | +| D.cs:24:16:24:18 | access to local variable ret : D [property AutoProp] : Object | semmle.label | access to local variable ret : D [property AutoProp] : Object | | D.cs:24:16:24:18 | access to local variable ret : D [property AutoProp] : Object | semmle.label | access to local variable ret : D [property AutoProp] : Object | | D.cs:29:17:29:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:29:17:29:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:31:17:31:37 | call to method Create : D [property AutoProp] : Object | semmle.label | call to method Create : D [property AutoProp] : Object | | D.cs:31:17:31:37 | call to method Create : D [property AutoProp] : Object | semmle.label | call to method Create : D [property AutoProp] : Object | | D.cs:31:24:31:24 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| D.cs:31:24:31:24 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| D.cs:32:14:32:14 | access to local variable d : D [property AutoProp] : Object | semmle.label | access to local variable d : D [property AutoProp] : Object | | D.cs:32:14:32:14 | access to local variable d : D [property AutoProp] : Object | semmle.label | access to local variable d : D [property AutoProp] : Object | | D.cs:32:14:32:23 | access to property AutoProp | semmle.label | access to property AutoProp | +| D.cs:32:14:32:23 | access to property AutoProp | semmle.label | access to property AutoProp | +| D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | semmle.label | call to method Create : D [field trivialPropField] : Object | | D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | semmle.label | call to method Create : D [field trivialPropField] : Object | | D.cs:37:26:37:42 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:37:26:37:42 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:39:14:39:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:39:14:39:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:39:14:39:26 | access to property TrivialProp | semmle.label | access to property TrivialProp | +| D.cs:39:14:39:26 | access to property TrivialProp | semmle.label | access to property TrivialProp | +| D.cs:40:14:40:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:40:14:40:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:40:14:40:31 | access to field trivialPropField | semmle.label | access to field trivialPropField | +| D.cs:40:14:40:31 | access to field trivialPropField | semmle.label | access to field trivialPropField | +| D.cs:41:14:41:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:41:14:41:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:41:14:41:26 | access to property ComplexProp | semmle.label | access to property ComplexProp | +| D.cs:41:14:41:26 | access to property ComplexProp | semmle.label | access to property ComplexProp | +| D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | semmle.label | call to method Create : D [field trivialPropField] : Object | | D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | semmle.label | call to method Create : D [field trivialPropField] : Object | | D.cs:43:32:43:48 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:43:32:43:48 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:45:14:45:26 | access to property TrivialProp | semmle.label | access to property TrivialProp | +| D.cs:45:14:45:26 | access to property TrivialProp | semmle.label | access to property TrivialProp | +| D.cs:46:14:46:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:46:14:46:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:46:14:46:31 | access to field trivialPropField | semmle.label | access to field trivialPropField | +| D.cs:46:14:46:31 | access to field trivialPropField | semmle.label | access to field trivialPropField | +| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | semmle.label | access to local variable d : D [field trivialPropField] : Object | | D.cs:47:14:47:26 | access to property ComplexProp | semmle.label | access to property ComplexProp | +| D.cs:47:14:47:26 | access to property ComplexProp | semmle.label | access to property ComplexProp | +| E.cs:8:29:8:29 | o : Object | semmle.label | o : Object | | E.cs:8:29:8:29 | o : Object | semmle.label | o : Object | | E.cs:11:9:11:11 | [post] access to local variable ret : S [field Field] : Object | semmle.label | [post] access to local variable ret : S [field Field] : Object | +| E.cs:11:9:11:11 | [post] access to local variable ret : S [field Field] : Object | semmle.label | [post] access to local variable ret : S [field Field] : Object | +| E.cs:11:21:11:21 | access to parameter o : Object | semmle.label | access to parameter o : Object | | E.cs:11:21:11:21 | access to parameter o : Object | semmle.label | access to parameter o : Object | | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | semmle.label | access to local variable ret : S [field Field] : Object | +| E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | semmle.label | access to local variable ret : S [field Field] : Object | +| E.cs:22:17:22:33 | call to method Source : Object | semmle.label | call to method Source : Object | | E.cs:22:17:22:33 | call to method Source : Object | semmle.label | call to method Source : Object | | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object | semmle.label | call to method CreateS : S [field Field] : Object | +| E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object | semmle.label | call to method CreateS : S [field Field] : Object | +| E.cs:23:25:23:25 | access to local variable o : Object | semmle.label | access to local variable o : Object | | E.cs:23:25:23:25 | access to local variable o : Object | semmle.label | access to local variable o : Object | | E.cs:24:14:24:14 | access to local variable s : S [field Field] : Object | semmle.label | access to local variable s : S [field Field] : Object | +| E.cs:24:14:24:14 | access to local variable s : S [field Field] : Object | semmle.label | access to local variable s : S [field Field] : Object | +| E.cs:24:14:24:20 | access to field Field | semmle.label | access to field Field | | E.cs:24:14:24:20 | access to field Field | semmle.label | access to field Field | | F.cs:6:28:6:29 | o1 : Object | semmle.label | o1 : Object | +| F.cs:6:28:6:29 | o1 : Object | semmle.label | o1 : Object | +| F.cs:6:39:6:40 | o2 : Object | semmle.label | o2 : Object | | F.cs:6:39:6:40 | o2 : Object | semmle.label | o2 : Object | | F.cs:6:46:6:81 | object creation of type F : F [field Field1] : Object | semmle.label | object creation of type F : F [field Field1] : Object | +| F.cs:6:46:6:81 | object creation of type F : F [field Field1] : Object | semmle.label | object creation of type F : F [field Field1] : Object | +| F.cs:6:46:6:81 | object creation of type F : F [field Field2] : Object | semmle.label | object creation of type F : F [field Field2] : Object | | F.cs:6:46:6:81 | object creation of type F : F [field Field2] : Object | semmle.label | object creation of type F : F [field Field2] : Object | | F.cs:6:54:6:81 | { ..., ... } : F [field Field1] : Object | semmle.label | { ..., ... } : F [field Field1] : Object | +| F.cs:6:54:6:81 | { ..., ... } : F [field Field1] : Object | semmle.label | { ..., ... } : F [field Field1] : Object | +| F.cs:6:54:6:81 | { ..., ... } : F [field Field2] : Object | semmle.label | { ..., ... } : F [field Field2] : Object | | F.cs:6:54:6:81 | { ..., ... } : F [field Field2] : Object | semmle.label | { ..., ... } : F [field Field2] : Object | | F.cs:6:65:6:66 | access to parameter o1 : Object | semmle.label | access to parameter o1 : Object | +| F.cs:6:65:6:66 | access to parameter o1 : Object | semmle.label | access to parameter o1 : Object | +| F.cs:6:78:6:79 | access to parameter o2 : Object | semmle.label | access to parameter o2 : Object | | F.cs:6:78:6:79 | access to parameter o2 : Object | semmle.label | access to parameter o2 : Object | | F.cs:10:17:10:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| F.cs:10:17:10:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| F.cs:11:17:11:31 | call to method Create : F [field Field1] : Object | semmle.label | call to method Create : F [field Field1] : Object | | F.cs:11:17:11:31 | call to method Create : F [field Field1] : Object | semmle.label | call to method Create : F [field Field1] : Object | | F.cs:11:24:11:24 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| F.cs:11:24:11:24 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| F.cs:12:14:12:14 | access to local variable f : F [field Field1] : Object | semmle.label | access to local variable f : F [field Field1] : Object | | F.cs:12:14:12:14 | access to local variable f : F [field Field1] : Object | semmle.label | access to local variable f : F [field Field1] : Object | | F.cs:12:14:12:21 | access to field Field1 | semmle.label | access to field Field1 | +| F.cs:12:14:12:21 | access to field Field1 | semmle.label | access to field Field1 | +| F.cs:15:13:15:43 | call to method Create : F [field Field2] : Object | semmle.label | call to method Create : F [field Field2] : Object | | F.cs:15:13:15:43 | call to method Create : F [field Field2] : Object | semmle.label | call to method Create : F [field Field2] : Object | | F.cs:15:26:15:42 | call to method Source : Object | semmle.label | call to method Source : Object | +| F.cs:15:26:15:42 | call to method Source : Object | semmle.label | call to method Source : Object | +| F.cs:17:14:17:14 | access to local variable f : F [field Field2] : Object | semmle.label | access to local variable f : F [field Field2] : Object | | F.cs:17:14:17:14 | access to local variable f : F [field Field2] : Object | semmle.label | access to local variable f : F [field Field2] : Object | | F.cs:17:14:17:21 | access to field Field2 | semmle.label | access to field Field2 | +| F.cs:17:14:17:21 | access to field Field2 | semmle.label | access to field Field2 | +| F.cs:19:21:19:50 | { ..., ... } : F [field Field1] : Object | semmle.label | { ..., ... } : F [field Field1] : Object | | F.cs:19:21:19:50 | { ..., ... } : F [field Field1] : Object | semmle.label | { ..., ... } : F [field Field1] : Object | | F.cs:19:32:19:48 | call to method Source : Object | semmle.label | call to method Source : Object | +| F.cs:19:32:19:48 | call to method Source : Object | semmle.label | call to method Source : Object | +| F.cs:20:14:20:14 | access to local variable f : F [field Field1] : Object | semmle.label | access to local variable f : F [field Field1] : Object | | F.cs:20:14:20:14 | access to local variable f : F [field Field1] : Object | semmle.label | access to local variable f : F [field Field1] : Object | | F.cs:20:14:20:21 | access to field Field1 | semmle.label | access to field Field1 | +| F.cs:20:14:20:21 | access to field Field1 | semmle.label | access to field Field1 | +| F.cs:23:21:23:50 | { ..., ... } : F [field Field2] : Object | semmle.label | { ..., ... } : F [field Field2] : Object | | F.cs:23:21:23:50 | { ..., ... } : F [field Field2] : Object | semmle.label | { ..., ... } : F [field Field2] : Object | | F.cs:23:32:23:48 | call to method Source : Object | semmle.label | call to method Source : Object | +| F.cs:23:32:23:48 | call to method Source : Object | semmle.label | call to method Source : Object | +| F.cs:25:14:25:14 | access to local variable f : F [field Field2] : Object | semmle.label | access to local variable f : F [field Field2] : Object | | F.cs:25:14:25:14 | access to local variable f : F [field Field2] : Object | semmle.label | access to local variable f : F [field Field2] : Object | | F.cs:25:14:25:21 | access to field Field2 | semmle.label | access to field Field2 | +| F.cs:25:14:25:21 | access to field Field2 | semmle.label | access to field Field2 | +| F.cs:30:17:30:33 | call to method Source : Object | semmle.label | call to method Source : Object | | F.cs:30:17:30:33 | call to method Source : Object | semmle.label | call to method Source : Object | | F.cs:32:17:32:40 | { ..., ... } : <>__AnonType0 [property X] : Object | semmle.label | { ..., ... } : <>__AnonType0 [property X] : Object | +| F.cs:32:17:32:40 | { ..., ... } : <>__AnonType0 [property X] : Object | semmle.label | { ..., ... } : <>__AnonType0 [property X] : Object | +| F.cs:32:27:32:27 | access to local variable o : Object | semmle.label | access to local variable o : Object | | F.cs:32:27:32:27 | access to local variable o : Object | semmle.label | access to local variable o : Object | | F.cs:33:14:33:14 | access to local variable a : <>__AnonType0 [property X] : Object | semmle.label | access to local variable a : <>__AnonType0 [property X] : Object | +| F.cs:33:14:33:14 | access to local variable a : <>__AnonType0 [property X] : Object | semmle.label | access to local variable a : <>__AnonType0 [property X] : Object | +| F.cs:33:14:33:16 | access to property X | semmle.label | access to property X | | F.cs:33:14:33:16 | access to property X | semmle.label | access to property X | | G.cs:7:18:7:32 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| G.cs:7:18:7:32 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| G.cs:9:9:9:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:9:9:9:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:9:9:9:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | semmle.label | [post] access to field Box1 : Box1 [field Elem] : Elem | +| G.cs:9:9:9:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | semmle.label | [post] access to field Box1 : Box1 [field Elem] : Elem | +| G.cs:9:23:9:23 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | | G.cs:9:23:9:23 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | | G.cs:10:18:10:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:10:18:10:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:15:18:15:32 | call to method Source : Elem | semmle.label | call to method Source : Elem | | G.cs:15:18:15:32 | call to method Source : Elem | semmle.label | call to method Source : Elem | | G.cs:17:9:17:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:17:9:17:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:17:9:17:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | semmle.label | [post] access to field Box1 : Box1 [field Elem] : Elem | | G.cs:17:9:17:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | semmle.label | [post] access to field Box1 : Box1 [field Elem] : Elem | | G.cs:17:24:17:24 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | +| G.cs:17:24:17:24 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | +| G.cs:18:18:18:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:18:18:18:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:23:18:23:32 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| G.cs:23:18:23:32 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| G.cs:25:9:25:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:25:9:25:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:25:9:25:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | semmle.label | [post] call to method GetBox1 : Box1 [field Elem] : Elem | +| G.cs:25:9:25:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | semmle.label | [post] call to method GetBox1 : Box1 [field Elem] : Elem | +| G.cs:25:28:25:28 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | | G.cs:25:28:25:28 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | | G.cs:26:18:26:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:26:18:26:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:31:18:31:32 | call to method Source : Elem | semmle.label | call to method Source : Elem | | G.cs:31:18:31:32 | call to method Source : Elem | semmle.label | call to method Source : Elem | | G.cs:33:9:33:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:33:9:33:9 | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | [post] access to local variable b : Box2 [field Box1, field Elem] : Elem | +| G.cs:33:9:33:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | semmle.label | [post] call to method GetBox1 : Box1 [field Elem] : Elem | | G.cs:33:9:33:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | semmle.label | [post] call to method GetBox1 : Box1 [field Elem] : Elem | | G.cs:33:29:33:29 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | +| G.cs:33:29:33:29 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | +| G.cs:34:18:34:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:34:18:34:18 | access to local variable b : Box2 [field Box1, field Elem] : Elem | semmle.label | access to local variable b : Box2 [field Box1, field Elem] : Elem | | G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | semmle.label | b2 : Box2 [field Box1, field Elem] : Elem | +| G.cs:37:38:37:39 | b2 : Box2 [field Box1, field Elem] : Elem | semmle.label | b2 : Box2 [field Box1, field Elem] : Elem | +| G.cs:39:14:39:15 | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | semmle.label | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | | G.cs:39:14:39:15 | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | semmle.label | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | | G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | semmle.label | call to method GetBox1 : Box1 [field Elem] : Elem | +| G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | semmle.label | call to method GetBox1 : Box1 [field Elem] : Elem | +| G.cs:39:14:39:35 | call to method GetElem | semmle.label | call to method GetElem | | G.cs:39:14:39:35 | call to method GetElem | semmle.label | call to method GetElem | | G.cs:44:18:44:32 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| G.cs:44:18:44:32 | call to method Source : Elem | semmle.label | call to method Source : Elem | +| G.cs:46:9:46:16 | [post] access to field boxfield : Box2 [field Box1, field Elem] : Elem | semmle.label | [post] access to field boxfield : Box2 [field Box1, field Elem] : Elem | | G.cs:46:9:46:16 | [post] access to field boxfield : Box2 [field Box1, field Elem] : Elem | semmle.label | [post] access to field boxfield : Box2 [field Box1, field Elem] : Elem | | G.cs:46:9:46:16 | [post] this access : G [field boxfield, field Box1, field Elem] : Elem | semmle.label | [post] this access : G [field boxfield, field Box1, field Elem] : Elem | +| G.cs:46:9:46:16 | [post] this access : G [field boxfield, field Box1, field Elem] : Elem | semmle.label | [post] this access : G [field boxfield, field Box1, field Elem] : Elem | +| G.cs:46:9:46:21 | [post] access to field Box1 : Box1 [field Elem] : Elem | semmle.label | [post] access to field Box1 : Box1 [field Elem] : Elem | | G.cs:46:9:46:21 | [post] access to field Box1 : Box1 [field Elem] : Elem | semmle.label | [post] access to field Box1 : Box1 [field Elem] : Elem | | G.cs:46:30:46:30 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | +| G.cs:46:30:46:30 | access to local variable e : Elem | semmle.label | access to local variable e : Elem | +| G.cs:47:9:47:13 | this access : G [field boxfield, field Box1, field Elem] : Elem | semmle.label | this access : G [field boxfield, field Box1, field Elem] : Elem | | G.cs:47:9:47:13 | this access : G [field boxfield, field Box1, field Elem] : Elem | semmle.label | this access : G [field boxfield, field Box1, field Elem] : Elem | | G.cs:50:18:50:20 | this : G [field boxfield, field Box1, field Elem] : Elem | semmle.label | this : G [field boxfield, field Box1, field Elem] : Elem | +| G.cs:50:18:50:20 | this : G [field boxfield, field Box1, field Elem] : Elem | semmle.label | this : G [field boxfield, field Box1, field Elem] : Elem | +| G.cs:52:14:52:21 | access to field boxfield : Box2 [field Box1, field Elem] : Elem | semmle.label | access to field boxfield : Box2 [field Box1, field Elem] : Elem | | G.cs:52:14:52:21 | access to field boxfield : Box2 [field Box1, field Elem] : Elem | semmle.label | access to field boxfield : Box2 [field Box1, field Elem] : Elem | | G.cs:52:14:52:21 | this access : G [field boxfield, field Box1, field Elem] : Elem | semmle.label | this access : G [field boxfield, field Box1, field Elem] : Elem | +| G.cs:52:14:52:21 | this access : G [field boxfield, field Box1, field Elem] : Elem | semmle.label | this access : G [field boxfield, field Box1, field Elem] : Elem | +| G.cs:52:14:52:26 | access to field Box1 : Box1 [field Elem] : Elem | semmle.label | access to field Box1 : Box1 [field Elem] : Elem | | G.cs:52:14:52:26 | access to field Box1 : Box1 [field Elem] : Elem | semmle.label | access to field Box1 : Box1 [field Elem] : Elem | | G.cs:52:14:52:31 | access to field Elem | semmle.label | access to field Elem | +| G.cs:52:14:52:31 | access to field Elem | semmle.label | access to field Elem | +| G.cs:63:21:63:27 | this : Box1 [field Elem] : Elem | semmle.label | this : Box1 [field Elem] : Elem | | G.cs:63:21:63:27 | this : Box1 [field Elem] : Elem | semmle.label | this : Box1 [field Elem] : Elem | | G.cs:63:34:63:37 | access to field Elem : Elem | semmle.label | access to field Elem : Elem | +| G.cs:63:34:63:37 | access to field Elem : Elem | semmle.label | access to field Elem : Elem | +| G.cs:63:34:63:37 | this access : Box1 [field Elem] : Elem | semmle.label | this access : Box1 [field Elem] : Elem | | G.cs:63:34:63:37 | this access : Box1 [field Elem] : Elem | semmle.label | this access : Box1 [field Elem] : Elem | | G.cs:64:34:64:34 | e : Elem | semmle.label | e : Elem | +| G.cs:64:34:64:34 | e : Elem | semmle.label | e : Elem | +| G.cs:64:39:64:42 | [post] this access : Box1 [field Elem] : Elem | semmle.label | [post] this access : Box1 [field Elem] : Elem | | G.cs:64:39:64:42 | [post] this access : Box1 [field Elem] : Elem | semmle.label | [post] this access : Box1 [field Elem] : Elem | | G.cs:64:46:64:46 | access to parameter e : Elem | semmle.label | access to parameter e : Elem | +| G.cs:64:46:64:46 | access to parameter e : Elem | semmle.label | access to parameter e : Elem | +| G.cs:71:21:71:27 | this : Box2 [field Box1, field Elem] : Elem | semmle.label | this : Box2 [field Box1, field Elem] : Elem | | G.cs:71:21:71:27 | this : Box2 [field Box1, field Elem] : Elem | semmle.label | this : Box2 [field Box1, field Elem] : Elem | | G.cs:71:34:71:37 | access to field Box1 : Box1 [field Elem] : Elem | semmle.label | access to field Box1 : Box1 [field Elem] : Elem | +| G.cs:71:34:71:37 | access to field Box1 : Box1 [field Elem] : Elem | semmle.label | access to field Box1 : Box1 [field Elem] : Elem | +| G.cs:71:34:71:37 | this access : Box2 [field Box1, field Elem] : Elem | semmle.label | this access : Box2 [field Box1, field Elem] : Elem | | G.cs:71:34:71:37 | this access : Box2 [field Box1, field Elem] : Elem | semmle.label | this access : Box2 [field Box1, field Elem] : Elem | | H.cs:13:15:13:15 | a : A [field FieldA] : Object | semmle.label | a : A [field FieldA] : Object | +| H.cs:13:15:13:15 | a : A [field FieldA] : Object | semmle.label | a : A [field FieldA] : Object | +| H.cs:16:9:16:11 | [post] access to local variable ret : A [field FieldA] : Object | semmle.label | [post] access to local variable ret : A [field FieldA] : Object | | H.cs:16:9:16:11 | [post] access to local variable ret : A [field FieldA] : Object | semmle.label | [post] access to local variable ret : A [field FieldA] : Object | | H.cs:16:22:16:22 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | +| H.cs:16:22:16:22 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | +| H.cs:16:22:16:29 | access to field FieldA : Object | semmle.label | access to field FieldA : Object | | H.cs:16:22:16:29 | access to field FieldA : Object | semmle.label | access to field FieldA : Object | | H.cs:17:16:17:18 | access to local variable ret : A [field FieldA] : Object | semmle.label | access to local variable ret : A [field FieldA] : Object | +| H.cs:17:16:17:18 | access to local variable ret : A [field FieldA] : Object | semmle.label | access to local variable ret : A [field FieldA] : Object | +| H.cs:23:9:23:9 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | | H.cs:23:9:23:9 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | | H.cs:23:20:23:36 | call to method Source : Object | semmle.label | call to method Source : Object | +| H.cs:23:20:23:36 | call to method Source : Object | semmle.label | call to method Source : Object | +| H.cs:24:21:24:28 | call to method Clone : A [field FieldA] : Object | semmle.label | call to method Clone : A [field FieldA] : Object | | H.cs:24:21:24:28 | call to method Clone : A [field FieldA] : Object | semmle.label | call to method Clone : A [field FieldA] : Object | | H.cs:24:27:24:27 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | +| H.cs:24:27:24:27 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | +| H.cs:25:14:25:18 | access to local variable clone : A [field FieldA] : Object | semmle.label | access to local variable clone : A [field FieldA] : Object | | H.cs:25:14:25:18 | access to local variable clone : A [field FieldA] : Object | semmle.label | access to local variable clone : A [field FieldA] : Object | | H.cs:25:14:25:25 | access to field FieldA | semmle.label | access to field FieldA | +| H.cs:25:14:25:25 | access to field FieldA | semmle.label | access to field FieldA | +| H.cs:33:19:33:19 | a : A [field FieldA] : A | semmle.label | a : A [field FieldA] : A | | H.cs:33:19:33:19 | a : A [field FieldA] : A | semmle.label | a : A [field FieldA] : A | | H.cs:33:19:33:19 | a : A [field FieldA] : Object | semmle.label | a : A [field FieldA] : Object | +| H.cs:33:19:33:19 | a : A [field FieldA] : Object | semmle.label | a : A [field FieldA] : Object | +| H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : A | semmle.label | [post] access to local variable b : B [field FieldB] : A | | H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : A | semmle.label | [post] access to local variable b : B [field FieldB] : A | | H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : Object | semmle.label | [post] access to local variable b : B [field FieldB] : Object | +| H.cs:36:9:36:9 | [post] access to local variable b : B [field FieldB] : Object | semmle.label | [post] access to local variable b : B [field FieldB] : Object | +| H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : A | semmle.label | access to parameter a : A [field FieldA] : A | | H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : A | semmle.label | access to parameter a : A [field FieldA] : A | | H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | +| H.cs:36:20:36:20 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | +| H.cs:36:20:36:27 | access to field FieldA : A | semmle.label | access to field FieldA : A | | H.cs:36:20:36:27 | access to field FieldA : A | semmle.label | access to field FieldA : A | | H.cs:36:20:36:27 | access to field FieldA : Object | semmle.label | access to field FieldA : Object | +| H.cs:36:20:36:27 | access to field FieldA : Object | semmle.label | access to field FieldA : Object | +| H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : A | semmle.label | access to local variable b : B [field FieldB] : A | | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : A | semmle.label | access to local variable b : B [field FieldB] : A | | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : Object | semmle.label | access to local variable b : B [field FieldB] : Object | +| H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : Object | semmle.label | access to local variable b : B [field FieldB] : Object | +| H.cs:43:9:43:9 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | | H.cs:43:9:43:9 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | | H.cs:43:20:43:36 | call to method Source : Object | semmle.label | call to method Source : Object | +| H.cs:43:20:43:36 | call to method Source : Object | semmle.label | call to method Source : Object | +| H.cs:44:17:44:28 | call to method Transform : B [field FieldB] : Object | semmle.label | call to method Transform : B [field FieldB] : Object | | H.cs:44:17:44:28 | call to method Transform : B [field FieldB] : Object | semmle.label | call to method Transform : B [field FieldB] : Object | | H.cs:44:27:44:27 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | +| H.cs:44:27:44:27 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | +| H.cs:45:14:45:14 | access to local variable b : B [field FieldB] : Object | semmle.label | access to local variable b : B [field FieldB] : Object | | H.cs:45:14:45:14 | access to local variable b : B [field FieldB] : Object | semmle.label | access to local variable b : B [field FieldB] : Object | | H.cs:45:14:45:21 | access to field FieldB | semmle.label | access to field FieldB | +| H.cs:45:14:45:21 | access to field FieldB | semmle.label | access to field FieldB | +| H.cs:53:25:53:25 | a : A [field FieldA] : Object | semmle.label | a : A [field FieldA] : Object | | H.cs:53:25:53:25 | a : A [field FieldA] : Object | semmle.label | a : A [field FieldA] : Object | | H.cs:55:9:55:10 | [post] access to parameter b1 : B [field FieldB] : Object | semmle.label | [post] access to parameter b1 : B [field FieldB] : Object | +| H.cs:55:9:55:10 | [post] access to parameter b1 : B [field FieldB] : Object | semmle.label | [post] access to parameter b1 : B [field FieldB] : Object | +| H.cs:55:21:55:21 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | | H.cs:55:21:55:21 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | | H.cs:55:21:55:28 | access to field FieldA : Object | semmle.label | access to field FieldA : Object | +| H.cs:55:21:55:28 | access to field FieldA : Object | semmle.label | access to field FieldA : Object | +| H.cs:63:9:63:9 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | | H.cs:63:9:63:9 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | | H.cs:63:20:63:36 | call to method Source : Object | semmle.label | call to method Source : Object | +| H.cs:63:20:63:36 | call to method Source : Object | semmle.label | call to method Source : Object | +| H.cs:64:22:64:22 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | | H.cs:64:22:64:22 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | | H.cs:64:25:64:26 | [post] access to local variable b1 : B [field FieldB] : Object | semmle.label | [post] access to local variable b1 : B [field FieldB] : Object | +| H.cs:64:25:64:26 | [post] access to local variable b1 : B [field FieldB] : Object | semmle.label | [post] access to local variable b1 : B [field FieldB] : Object | +| H.cs:65:14:65:15 | access to local variable b1 : B [field FieldB] : Object | semmle.label | access to local variable b1 : B [field FieldB] : Object | | H.cs:65:14:65:15 | access to local variable b1 : B [field FieldB] : Object | semmle.label | access to local variable b1 : B [field FieldB] : Object | | H.cs:65:14:65:22 | access to field FieldB | semmle.label | access to field FieldB | +| H.cs:65:14:65:22 | access to field FieldB | semmle.label | access to field FieldB | +| H.cs:77:30:77:30 | o : Object | semmle.label | o : Object | | H.cs:77:30:77:30 | o : Object | semmle.label | o : Object | | H.cs:79:9:79:9 | [post] access to parameter a : A [field FieldA] : Object | semmle.label | [post] access to parameter a : A [field FieldA] : Object | +| H.cs:79:9:79:9 | [post] access to parameter a : A [field FieldA] : Object | semmle.label | [post] access to parameter a : A [field FieldA] : Object | +| H.cs:79:20:79:20 | access to parameter o : Object | semmle.label | access to parameter o : Object | | H.cs:79:20:79:20 | access to parameter o : Object | semmle.label | access to parameter o : Object | | H.cs:80:22:80:22 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | +| H.cs:80:22:80:22 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | +| H.cs:80:25:80:26 | [post] access to parameter b1 : B [field FieldB] : Object | semmle.label | [post] access to parameter b1 : B [field FieldB] : Object | | H.cs:80:25:80:26 | [post] access to parameter b1 : B [field FieldB] : Object | semmle.label | [post] access to parameter b1 : B [field FieldB] : Object | | H.cs:88:17:88:17 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:88:17:88:17 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:88:20:88:36 | call to method Source : Object | semmle.label | call to method Source : Object | | H.cs:88:20:88:36 | call to method Source : Object | semmle.label | call to method Source : Object | | H.cs:88:39:88:40 | [post] access to local variable b1 : B [field FieldB] : Object | semmle.label | [post] access to local variable b1 : B [field FieldB] : Object | +| H.cs:88:39:88:40 | [post] access to local variable b1 : B [field FieldB] : Object | semmle.label | [post] access to local variable b1 : B [field FieldB] : Object | +| H.cs:89:14:89:14 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | | H.cs:89:14:89:14 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | | H.cs:89:14:89:21 | access to field FieldA | semmle.label | access to field FieldA | +| H.cs:89:14:89:21 | access to field FieldA | semmle.label | access to field FieldA | +| H.cs:90:14:90:15 | access to local variable b1 : B [field FieldB] : Object | semmle.label | access to local variable b1 : B [field FieldB] : Object | | H.cs:90:14:90:15 | access to local variable b1 : B [field FieldB] : Object | semmle.label | access to local variable b1 : B [field FieldB] : Object | | H.cs:90:14:90:22 | access to field FieldB | semmle.label | access to field FieldB | +| H.cs:90:14:90:22 | access to field FieldB | semmle.label | access to field FieldB | +| H.cs:102:23:102:23 | a : A [field FieldA] : Object | semmle.label | a : A [field FieldA] : Object | | H.cs:102:23:102:23 | a : A [field FieldA] : Object | semmle.label | a : A [field FieldA] : Object | | H.cs:105:9:105:12 | [post] access to local variable temp : B [field FieldB, field FieldA] : Object | semmle.label | [post] access to local variable temp : B [field FieldB, field FieldA] : Object | +| H.cs:105:9:105:12 | [post] access to local variable temp : B [field FieldB, field FieldA] : Object | semmle.label | [post] access to local variable temp : B [field FieldB, field FieldA] : Object | +| H.cs:105:23:105:23 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | | H.cs:105:23:105:23 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | | H.cs:106:16:106:40 | call to method Transform : B [field FieldB] : Object | semmle.label | call to method Transform : B [field FieldB] : Object | +| H.cs:106:16:106:40 | call to method Transform : B [field FieldB] : Object | semmle.label | call to method Transform : B [field FieldB] : Object | +| H.cs:106:26:106:39 | (...) ... : A [field FieldA] : Object | semmle.label | (...) ... : A [field FieldA] : Object | | H.cs:106:26:106:39 | (...) ... : A [field FieldA] : Object | semmle.label | (...) ... : A [field FieldA] : Object | | H.cs:106:29:106:32 | access to local variable temp : B [field FieldB, field FieldA] : Object | semmle.label | access to local variable temp : B [field FieldB, field FieldA] : Object | +| H.cs:106:29:106:32 | access to local variable temp : B [field FieldB, field FieldA] : Object | semmle.label | access to local variable temp : B [field FieldB, field FieldA] : Object | +| H.cs:106:29:106:39 | access to field FieldB : A [field FieldA] : Object | semmle.label | access to field FieldB : A [field FieldA] : Object | | H.cs:106:29:106:39 | access to field FieldB : A [field FieldA] : Object | semmle.label | access to field FieldB : A [field FieldA] : Object | | H.cs:112:9:112:9 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:112:9:112:9 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:112:20:112:36 | call to method Source : Object | semmle.label | call to method Source : Object | | H.cs:112:20:112:36 | call to method Source : Object | semmle.label | call to method Source : Object | | H.cs:113:17:113:32 | call to method TransformWrap : B [field FieldB] : Object | semmle.label | call to method TransformWrap : B [field FieldB] : Object | +| H.cs:113:17:113:32 | call to method TransformWrap : B [field FieldB] : Object | semmle.label | call to method TransformWrap : B [field FieldB] : Object | +| H.cs:113:31:113:31 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | | H.cs:113:31:113:31 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | | H.cs:114:14:114:14 | access to local variable b : B [field FieldB] : Object | semmle.label | access to local variable b : B [field FieldB] : Object | +| H.cs:114:14:114:14 | access to local variable b : B [field FieldB] : Object | semmle.label | access to local variable b : B [field FieldB] : Object | +| H.cs:114:14:114:21 | access to field FieldB | semmle.label | access to field FieldB | | H.cs:114:14:114:21 | access to field FieldB | semmle.label | access to field FieldB | | H.cs:122:18:122:18 | a : A [field FieldA] : Object | semmle.label | a : A [field FieldA] : Object | +| H.cs:122:18:122:18 | a : A [field FieldA] : Object | semmle.label | a : A [field FieldA] : Object | +| H.cs:124:16:124:27 | call to method Transform : B [field FieldB] : Object | semmle.label | call to method Transform : B [field FieldB] : Object | | H.cs:124:16:124:27 | call to method Transform : B [field FieldB] : Object | semmle.label | call to method Transform : B [field FieldB] : Object | | H.cs:124:16:124:34 | access to field FieldB : Object | semmle.label | access to field FieldB : Object | +| H.cs:124:16:124:34 | access to field FieldB : Object | semmle.label | access to field FieldB : Object | +| H.cs:124:26:124:26 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | | H.cs:124:26:124:26 | access to parameter a : A [field FieldA] : Object | semmle.label | access to parameter a : A [field FieldA] : Object | | H.cs:130:9:130:9 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:130:9:130:9 | [post] access to local variable a : A [field FieldA] : Object | semmle.label | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:130:20:130:36 | call to method Source : Object | semmle.label | call to method Source : Object | | H.cs:130:20:130:36 | call to method Source : Object | semmle.label | call to method Source : Object | | H.cs:131:14:131:19 | call to method Get | semmle.label | call to method Get | +| H.cs:131:14:131:19 | call to method Get | semmle.label | call to method Get | +| H.cs:131:18:131:18 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | | H.cs:131:18:131:18 | access to local variable a : A [field FieldA] : Object | semmle.label | access to local variable a : A [field FieldA] : Object | | H.cs:138:27:138:27 | o : A | semmle.label | o : A | +| H.cs:138:27:138:27 | o : A | semmle.label | o : A | +| H.cs:141:9:141:9 | [post] access to local variable a : A [field FieldA] : A | semmle.label | [post] access to local variable a : A [field FieldA] : A | | H.cs:141:9:141:9 | [post] access to local variable a : A [field FieldA] : A | semmle.label | [post] access to local variable a : A [field FieldA] : A | | H.cs:141:20:141:25 | ... as ... : A | semmle.label | ... as ... : A | +| H.cs:141:20:141:25 | ... as ... : A | semmle.label | ... as ... : A | +| H.cs:142:16:142:27 | call to method Transform : B [field FieldB] : A | semmle.label | call to method Transform : B [field FieldB] : A | | H.cs:142:16:142:27 | call to method Transform : B [field FieldB] : A | semmle.label | call to method Transform : B [field FieldB] : A | | H.cs:142:16:142:34 | access to field FieldB : A | semmle.label | access to field FieldB : A | +| H.cs:142:16:142:34 | access to field FieldB : A | semmle.label | access to field FieldB : A | +| H.cs:142:26:142:26 | access to local variable a : A [field FieldA] : A | semmle.label | access to local variable a : A [field FieldA] : A | | H.cs:142:26:142:26 | access to local variable a : A [field FieldA] : A | semmle.label | access to local variable a : A [field FieldA] : A | | H.cs:147:17:147:39 | call to method Through : A | semmle.label | call to method Through : A | +| H.cs:147:17:147:39 | call to method Through : A | semmle.label | call to method Through : A | +| H.cs:147:25:147:38 | call to method Source : A | semmle.label | call to method Source : A | | H.cs:147:25:147:38 | call to method Source : A | semmle.label | call to method Source : A | | H.cs:148:14:148:14 | access to local variable a | semmle.label | access to local variable a | +| H.cs:148:14:148:14 | access to local variable a | semmle.label | access to local variable a | +| H.cs:153:32:153:32 | o : Object | semmle.label | o : Object | | H.cs:153:32:153:32 | o : Object | semmle.label | o : Object | | H.cs:155:17:155:30 | call to method Source : B | semmle.label | call to method Source : B | +| H.cs:155:17:155:30 | call to method Source : B | semmle.label | call to method Source : B | +| H.cs:156:9:156:9 | [post] access to local variable b : B [field FieldB] : Object | semmle.label | [post] access to local variable b : B [field FieldB] : Object | | H.cs:156:9:156:9 | [post] access to local variable b : B [field FieldB] : Object | semmle.label | [post] access to local variable b : B [field FieldB] : Object | | H.cs:156:9:156:9 | access to local variable b : B | semmle.label | access to local variable b : B | +| H.cs:156:9:156:9 | access to local variable b : B | semmle.label | access to local variable b : B | +| H.cs:156:20:156:20 | access to parameter o : Object | semmle.label | access to parameter o : Object | | H.cs:156:20:156:20 | access to parameter o : Object | semmle.label | access to parameter o : Object | | H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA, field FieldB] : Object | semmle.label | [post] access to parameter a : A [field FieldA, field FieldB] : Object | +| H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA, field FieldB] : Object | semmle.label | [post] access to parameter a : A [field FieldA, field FieldB] : Object | +| H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA] : B | semmle.label | [post] access to parameter a : A [field FieldA] : B | | H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA] : B | semmle.label | [post] access to parameter a : A [field FieldA] : B | | H.cs:157:20:157:20 | access to local variable b : B | semmle.label | access to local variable b : B | +| H.cs:157:20:157:20 | access to local variable b : B | semmle.label | access to local variable b : B | +| H.cs:157:20:157:20 | access to local variable b : B [field FieldB] : Object | semmle.label | access to local variable b : B [field FieldB] : Object | | H.cs:157:20:157:20 | access to local variable b : B [field FieldB] : Object | semmle.label | access to local variable b : B [field FieldB] : Object | | H.cs:163:17:163:35 | call to method Source : Object | semmle.label | call to method Source : Object | +| H.cs:163:17:163:35 | call to method Source : Object | semmle.label | call to method Source : Object | +| H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA, field FieldB] : Object | semmle.label | [post] access to local variable a : A [field FieldA, field FieldB] : Object | | H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA, field FieldB] : Object | semmle.label | [post] access to local variable a : A [field FieldA, field FieldB] : Object | | H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA] : B | semmle.label | [post] access to local variable a : A [field FieldA] : B | +| H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA] : B | semmle.label | [post] access to local variable a : A [field FieldA] : B | +| H.cs:164:22:164:22 | access to local variable o : Object | semmle.label | access to local variable o : Object | | 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:27 | (...) ... : B | semmle.label | (...) ... : B | +| H.cs:165:17:165:27 | (...) ... : B | semmle.label | (...) ... : B | +| H.cs:165:17:165:27 | (...) ... : B [field FieldB] : Object | semmle.label | (...) ... : B [field FieldB] : Object | | H.cs:165:17:165:27 | (...) ... : B [field FieldB] : Object | semmle.label | (...) ... : B [field FieldB] : Object | | H.cs:165:20:165:20 | access to local variable a : A [field FieldA, field FieldB] : Object | semmle.label | access to local variable a : A [field FieldA, field FieldB] : Object | +| H.cs:165:20:165:20 | access to local variable a : A [field FieldA, field FieldB] : Object | semmle.label | access to local variable a : A [field FieldA, field FieldB] : Object | +| H.cs:165:20:165:20 | access to local variable a : A [field FieldA] : B | semmle.label | access to local variable a : A [field FieldA] : B | | H.cs:165:20:165:20 | access to local variable a : A [field FieldA] : B | semmle.label | access to local variable a : A [field FieldA] : B | | H.cs:165:20:165:27 | access to field FieldA : B | semmle.label | access to field FieldA : B | +| H.cs:165:20:165:27 | access to field FieldA : B | semmle.label | access to field FieldA : B | +| H.cs:165:20:165:27 | access to field FieldA : B [field FieldB] : Object | semmle.label | access to field FieldA : B [field FieldB] : Object | | H.cs:165:20:165:27 | access to field FieldA : B [field FieldB] : Object | semmle.label | access to field FieldA : B [field FieldB] : Object | | H.cs:166:14:166:14 | access to local variable b | semmle.label | access to local variable b | +| 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 : B [field FieldB] : Object | semmle.label | access to local variable b : B [field FieldB] : Object | | H.cs:167:14:167:14 | access to local variable b : B [field FieldB] : Object | semmle.label | access to local variable b : B [field FieldB] : Object | | H.cs:167:14:167:21 | access to field FieldB | semmle.label | access to field FieldB | +| H.cs:167:14:167:21 | access to field FieldB | semmle.label | access to field FieldB | +| I.cs:7:9:7:14 | [post] this access : I [field Field1] : Object | semmle.label | [post] this access : I [field Field1] : Object | | I.cs:7:9:7:14 | [post] this access : I [field Field1] : Object | semmle.label | [post] this access : I [field Field1] : Object | | I.cs:7:18:7:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| I.cs:7:18:7:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| I.cs:13:17:13:33 | call to method Source : Object | semmle.label | call to method Source : Object | | I.cs:13:17:13:33 | call to method Source : Object | semmle.label | call to method Source : Object | | I.cs:15:9:15:9 | [post] access to local variable i : I [field Field1] : Object | semmle.label | [post] access to local variable i : I [field Field1] : Object | +| I.cs:15:9:15:9 | [post] access to local variable i : I [field Field1] : Object | semmle.label | [post] access to local variable i : I [field Field1] : Object | +| I.cs:15:20:15:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | | I.cs:15:20:15:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | | I.cs:16:9:16:9 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | +| I.cs:16:9:16:9 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | +| I.cs:17:9:17:9 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | | I.cs:17:9:17:9 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | | I.cs:18:14:18:14 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | +| I.cs:18:14:18:14 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | +| I.cs:18:14:18:21 | access to field Field1 | semmle.label | access to field Field1 | | I.cs:18:14:18:21 | access to field Field1 | semmle.label | access to field Field1 | | I.cs:21:13:21:19 | object creation of type I : I [field Field1] : Object | semmle.label | object creation of type I : I [field Field1] : Object | +| I.cs:21:13:21:19 | object creation of type I : I [field Field1] : Object | semmle.label | object creation of type I : I [field Field1] : Object | +| I.cs:22:9:22:9 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | | I.cs:22:9:22:9 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | | I.cs:23:14:23:14 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | +| I.cs:23:14:23:14 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | +| I.cs:23:14:23:21 | access to field Field1 | semmle.label | access to field Field1 | | I.cs:23:14:23:21 | access to field Field1 | semmle.label | access to field Field1 | | I.cs:26:13:26:37 | [pre-initializer] object creation of type I : I [field Field1] : Object | semmle.label | [pre-initializer] object creation of type I : I [field Field1] : Object | +| I.cs:26:13:26:37 | [pre-initializer] object creation of type I : I [field Field1] : Object | semmle.label | [pre-initializer] object creation of type I : I [field Field1] : Object | +| I.cs:27:14:27:14 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | | I.cs:27:14:27:14 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | | I.cs:27:14:27:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:27:14:27:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:31:13:31:29 | call to method Source : Object | semmle.label | call to method Source : Object | | I.cs:31:13:31:29 | call to method Source : Object | semmle.label | call to method Source : Object | | I.cs:32:9:32:9 | [post] access to local variable i : I [field Field1] : Object | semmle.label | [post] access to local variable i : I [field Field1] : Object | +| I.cs:32:9:32:9 | [post] access to local variable i : I [field Field1] : Object | semmle.label | [post] access to local variable i : I [field Field1] : Object | +| I.cs:32:20:32:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | | I.cs:32:20:32:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | | I.cs:33:9:33:9 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | +| I.cs:33:9:33:9 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | +| I.cs:34:12:34:12 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | | I.cs:34:12:34:12 | access to local variable i : I [field Field1] : Object | semmle.label | access to local variable i : I [field Field1] : Object | | I.cs:37:23:37:23 | i : I [field Field1] : Object | semmle.label | i : I [field Field1] : Object | +| I.cs:37:23:37:23 | i : I [field Field1] : Object | semmle.label | i : I [field Field1] : Object | +| I.cs:39:9:39:9 | access to parameter i : I [field Field1] : Object | semmle.label | access to parameter i : I [field Field1] : Object | | I.cs:39:9:39:9 | access to parameter i : I [field Field1] : Object | semmle.label | access to parameter i : I [field Field1] : Object | | I.cs:40:14:40:14 | access to parameter i : I [field Field1] : Object | semmle.label | access to parameter i : I [field Field1] : Object | +| I.cs:40:14:40:14 | access to parameter i : I [field Field1] : Object | semmle.label | access to parameter i : I [field Field1] : Object | +| I.cs:40:14:40:21 | access to field Field1 | semmle.label | access to field Field1 | | I.cs:40:14:40:21 | access to field Field1 | semmle.label | access to field Field1 | | J.cs:14:26:14:30 | field : Object | semmle.label | field : Object | +| J.cs:14:26:14:30 | field : Object | semmle.label | field : Object | +| J.cs:14:40:14:43 | prop : Object | semmle.label | prop : Object | | J.cs:14:40:14:43 | prop : Object | semmle.label | prop : Object | | J.cs:14:50:14:54 | [post] this access : Struct [field Field] : Object | semmle.label | [post] this access : Struct [field Field] : Object | +| J.cs:14:50:14:54 | [post] this access : Struct [field Field] : Object | semmle.label | [post] this access : Struct [field Field] : Object | +| J.cs:14:57:14:60 | [post] this access : Struct [property Prop] : Object | semmle.label | [post] this access : Struct [property Prop] : Object | | J.cs:14:57:14:60 | [post] this access : Struct [property Prop] : Object | semmle.label | [post] this access : Struct [property Prop] : Object | | J.cs:14:66:14:70 | access to parameter field : Object | semmle.label | access to parameter field : Object | +| J.cs:14:66:14:70 | access to parameter field : Object | semmle.label | access to parameter field : Object | +| J.cs:14:73:14:76 | access to parameter prop : Object | semmle.label | access to parameter prop : Object | | J.cs:14:73:14:76 | access to parameter prop : Object | semmle.label | access to parameter prop : Object | | J.cs:21:17:21:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:21:17:21:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | semmle.label | object creation of type RecordClass : RecordClass [property Prop1] : Object | | J.cs:22:18:22:41 | object creation of type RecordClass : RecordClass [property Prop1] : Object | semmle.label | object creation of type RecordClass : RecordClass [property Prop1] : Object | | J.cs:22:34:22:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| J.cs:22:34:22:34 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| J.cs:23:14:23:15 | access to local variable r1 : RecordClass [property Prop1] : Object | semmle.label | access to local variable r1 : RecordClass [property Prop1] : Object | | J.cs:23:14:23:15 | access to local variable r1 : RecordClass [property Prop1] : Object | semmle.label | access to local variable r1 : RecordClass [property Prop1] : Object | | J.cs:23:14:23:21 | access to property Prop1 | semmle.label | access to property Prop1 | +| J.cs:23:14:23:21 | access to property Prop1 | semmle.label | access to property Prop1 | +| J.cs:27:14:27:15 | access to local variable r2 : RecordClass [property Prop1] : Object | semmle.label | access to local variable r2 : RecordClass [property Prop1] : Object | | J.cs:27:14:27:15 | access to local variable r2 : RecordClass [property Prop1] : Object | semmle.label | access to local variable r2 : RecordClass [property Prop1] : Object | | J.cs:27:14:27:21 | access to property Prop1 | semmle.label | access to property Prop1 | +| J.cs:27:14:27:21 | access to property Prop1 | semmle.label | access to property Prop1 | +| J.cs:30:18:30:54 | ... with { ... } : RecordClass [property Prop2] : Object | semmle.label | ... with { ... } : RecordClass [property Prop2] : Object | | J.cs:30:18:30:54 | ... with { ... } : RecordClass [property Prop2] : Object | semmle.label | ... with { ... } : RecordClass [property Prop2] : Object | | J.cs:30:36:30:52 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:30:36:30:52 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:31:14:31:15 | access to local variable r3 : RecordClass [property Prop1] : Object | semmle.label | access to local variable r3 : RecordClass [property Prop1] : Object | | J.cs:31:14:31:15 | access to local variable r3 : RecordClass [property Prop1] : Object | semmle.label | access to local variable r3 : RecordClass [property Prop1] : Object | | J.cs:31:14:31:21 | access to property Prop1 | semmle.label | access to property Prop1 | +| J.cs:31:14:31:21 | access to property Prop1 | semmle.label | access to property Prop1 | +| J.cs:32:14:32:15 | access to local variable r3 : RecordClass [property Prop2] : Object | semmle.label | access to local variable r3 : RecordClass [property Prop2] : Object | | J.cs:32:14:32:15 | access to local variable r3 : RecordClass [property Prop2] : Object | semmle.label | access to local variable r3 : RecordClass [property Prop2] : Object | | J.cs:32:14:32:21 | access to property Prop2 | semmle.label | access to property Prop2 | +| J.cs:32:14:32:21 | access to property Prop2 | semmle.label | access to property Prop2 | +| J.cs:41:17:41:33 | call to method Source : Object | semmle.label | call to method Source : Object | | J.cs:41:17:41:33 | call to method Source : Object | semmle.label | call to method Source : Object | | J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | semmle.label | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | +| J.cs:42:18:42:42 | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | semmle.label | object creation of type RecordStruct : RecordStruct [property Prop1] : Object | +| J.cs:42:35:42:35 | access to local variable o : Object | semmle.label | access to local variable o : Object | | J.cs:42:35:42:35 | access to local variable o : Object | semmle.label | access to local variable o : Object | | J.cs:43:14:43:15 | access to local variable r1 : RecordStruct [property Prop1] : Object | semmle.label | access to local variable r1 : RecordStruct [property Prop1] : Object | +| J.cs:43:14:43:15 | access to local variable r1 : RecordStruct [property Prop1] : Object | semmle.label | access to local variable r1 : RecordStruct [property Prop1] : Object | +| J.cs:43:14:43:21 | access to property Prop1 | semmle.label | access to property Prop1 | | J.cs:43:14:43:21 | access to property Prop1 | semmle.label | access to property Prop1 | | J.cs:47:14:47:15 | access to local variable r2 : RecordStruct [property Prop1] : Object | semmle.label | access to local variable r2 : RecordStruct [property Prop1] : Object | +| J.cs:47:14:47:15 | access to local variable r2 : RecordStruct [property Prop1] : Object | semmle.label | access to local variable r2 : RecordStruct [property Prop1] : Object | +| J.cs:47:14:47:21 | access to property Prop1 | semmle.label | access to property Prop1 | | J.cs:47:14:47:21 | access to property Prop1 | semmle.label | access to property Prop1 | | J.cs:50:18:50:54 | ... with { ... } : RecordStruct [property Prop2] : Object | semmle.label | ... with { ... } : RecordStruct [property Prop2] : Object | +| J.cs:50:18:50:54 | ... with { ... } : RecordStruct [property Prop2] : Object | semmle.label | ... with { ... } : RecordStruct [property Prop2] : Object | +| J.cs:50:36:50:52 | call to method Source : Object | semmle.label | call to method Source : Object | | J.cs:50:36:50:52 | call to method Source : Object | semmle.label | call to method Source : Object | | J.cs:51:14:51:15 | access to local variable r3 : RecordStruct [property Prop1] : Object | semmle.label | access to local variable r3 : RecordStruct [property Prop1] : Object | +| J.cs:51:14:51:15 | access to local variable r3 : RecordStruct [property Prop1] : Object | semmle.label | access to local variable r3 : RecordStruct [property Prop1] : Object | +| J.cs:51:14:51:21 | access to property Prop1 | semmle.label | access to property Prop1 | | J.cs:51:14:51:21 | access to property Prop1 | semmle.label | access to property Prop1 | | J.cs:52:14:52:15 | access to local variable r3 : RecordStruct [property Prop2] : Object | semmle.label | access to local variable r3 : RecordStruct [property Prop2] : Object | +| J.cs:52:14:52:15 | access to local variable r3 : RecordStruct [property Prop2] : Object | semmle.label | access to local variable r3 : RecordStruct [property Prop2] : Object | +| J.cs:52:14:52:21 | access to property Prop2 | semmle.label | access to property Prop2 | | J.cs:52:14:52:21 | access to property Prop2 | semmle.label | access to property Prop2 | | J.cs:61:17:61:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:61:17:61:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object | semmle.label | object creation of type Struct : Struct [field Field] : Object | | J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object | semmle.label | object creation of type Struct : Struct [field Field] : Object | | J.cs:62:29:62:29 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| J.cs:62:29:62:29 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| J.cs:65:14:65:15 | access to local variable s2 : Struct [field Field] : Object | semmle.label | access to local variable s2 : Struct [field Field] : Object | | J.cs:65:14:65:15 | access to local variable s2 : Struct [field Field] : Object | semmle.label | access to local variable s2 : Struct [field Field] : Object | | J.cs:65:14:65:21 | access to field Field | semmle.label | access to field Field | +| J.cs:65:14:65:21 | access to field Field | semmle.label | access to field Field | +| J.cs:68:18:68:53 | ... with { ... } : Struct [property Prop] : Object | semmle.label | ... with { ... } : Struct [property Prop] : Object | | J.cs:68:18:68:53 | ... with { ... } : Struct [property Prop] : Object | semmle.label | ... with { ... } : Struct [property Prop] : Object | | J.cs:68:35:68:51 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:68:35:68:51 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:69:14:69:15 | access to local variable s3 : Struct [field Field] : Object | semmle.label | access to local variable s3 : Struct [field Field] : Object | | J.cs:69:14:69:15 | access to local variable s3 : Struct [field Field] : Object | semmle.label | access to local variable s3 : Struct [field Field] : Object | | J.cs:69:14:69:21 | access to field Field | semmle.label | access to field Field | +| J.cs:69:14:69:21 | access to field Field | semmle.label | access to field Field | +| J.cs:70:14:70:15 | access to local variable s3 : Struct [property Prop] : Object | semmle.label | access to local variable s3 : Struct [property Prop] : Object | | J.cs:70:14:70:15 | access to local variable s3 : Struct [property Prop] : Object | semmle.label | access to local variable s3 : Struct [property Prop] : Object | | J.cs:70:14:70:20 | access to property Prop | semmle.label | access to property Prop | +| J.cs:70:14:70:20 | access to property Prop | semmle.label | access to property Prop | +| J.cs:79:17:79:33 | call to method Source : Object | semmle.label | call to method Source : Object | | J.cs:79:17:79:33 | call to method Source : Object | semmle.label | call to method Source : Object | | J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object | semmle.label | object creation of type Struct : Struct [property Prop] : Object | +| J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object | semmle.label | object creation of type Struct : Struct [property Prop] : Object | +| J.cs:80:35:80:35 | access to local variable o : Object | semmle.label | access to local variable o : Object | | J.cs:80:35:80:35 | access to local variable o : Object | semmle.label | access to local variable o : Object | | J.cs:84:14:84:15 | access to local variable s2 : Struct [property Prop] : Object | semmle.label | access to local variable s2 : Struct [property Prop] : Object | +| J.cs:84:14:84:15 | access to local variable s2 : Struct [property Prop] : Object | semmle.label | access to local variable s2 : Struct [property Prop] : Object | +| J.cs:84:14:84:20 | access to property Prop | semmle.label | access to property Prop | | J.cs:84:14:84:20 | access to property Prop | semmle.label | access to property Prop | | J.cs:86:18:86:54 | ... with { ... } : Struct [field Field] : Object | semmle.label | ... with { ... } : Struct [field Field] : Object | +| J.cs:86:18:86:54 | ... with { ... } : Struct [field Field] : Object | semmle.label | ... with { ... } : Struct [field Field] : Object | +| J.cs:86:36:86:52 | call to method Source : Object | semmle.label | call to method Source : Object | | J.cs:86:36:86:52 | call to method Source : Object | semmle.label | call to method Source : Object | | J.cs:87:14:87:15 | access to local variable s3 : Struct [field Field] : Object | semmle.label | access to local variable s3 : Struct [field Field] : Object | +| J.cs:87:14:87:15 | access to local variable s3 : Struct [field Field] : Object | semmle.label | access to local variable s3 : Struct [field Field] : Object | +| J.cs:87:14:87:21 | access to field Field | semmle.label | access to field Field | | J.cs:87:14:87:21 | access to field Field | semmle.label | access to field Field | | J.cs:88:14:88:15 | access to local variable s3 : Struct [property Prop] : Object | semmle.label | access to local variable s3 : Struct [property Prop] : Object | +| J.cs:88:14:88:15 | access to local variable s3 : Struct [property Prop] : Object | semmle.label | access to local variable s3 : Struct [property Prop] : Object | +| J.cs:88:14:88:20 | access to property Prop | semmle.label | access to property Prop | | J.cs:88:14:88:20 | access to property Prop | semmle.label | access to property Prop | | J.cs:97:17:97:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:97:17:97:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:99:18:99:41 | { ..., ... } : <>__AnonType0 [property X] : Object | semmle.label | { ..., ... } : <>__AnonType0 [property X] : Object | | J.cs:99:18:99:41 | { ..., ... } : <>__AnonType0 [property X] : Object | semmle.label | { ..., ... } : <>__AnonType0 [property X] : Object | | J.cs:99:28:99:28 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| J.cs:99:28:99:28 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| J.cs:102:14:102:15 | access to local variable a2 : <>__AnonType0 [property X] : Object | semmle.label | access to local variable a2 : <>__AnonType0 [property X] : Object | | J.cs:102:14:102:15 | access to local variable a2 : <>__AnonType0 [property X] : Object | semmle.label | access to local variable a2 : <>__AnonType0 [property X] : Object | | J.cs:102:14:102:17 | access to property X | semmle.label | access to property X | +| J.cs:102:14:102:17 | access to property X | semmle.label | access to property X | +| J.cs:105:18:105:50 | ... with { ... } : <>__AnonType0 [property Y] : Object | semmle.label | ... with { ... } : <>__AnonType0 [property Y] : Object | | J.cs:105:18:105:50 | ... with { ... } : <>__AnonType0 [property Y] : Object | semmle.label | ... with { ... } : <>__AnonType0 [property Y] : Object | | J.cs:105:32:105:48 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:105:32:105:48 | call to method Source : Object | semmle.label | call to method Source : Object | +| J.cs:106:14:106:15 | access to local variable a3 : <>__AnonType0 [property X] : Object | semmle.label | access to local variable a3 : <>__AnonType0 [property X] : Object | | J.cs:106:14:106:15 | access to local variable a3 : <>__AnonType0 [property X] : Object | semmle.label | access to local variable a3 : <>__AnonType0 [property X] : Object | | J.cs:106:14:106:17 | access to property X | semmle.label | access to property X | +| J.cs:106:14:106:17 | access to property X | semmle.label | access to property X | +| J.cs:107:14:107:15 | access to local variable a3 : <>__AnonType0 [property Y] : Object | semmle.label | access to local variable a3 : <>__AnonType0 [property Y] : Object | | J.cs:107:14:107:15 | access to local variable a3 : <>__AnonType0 [property Y] : Object | semmle.label | access to local variable a3 : <>__AnonType0 [property Y] : Object | | J.cs:107:14:107:17 | access to property Y | semmle.label | access to property Y | +| J.cs:107:14:107:17 | access to property Y | semmle.label | access to property Y | +| J.cs:119:13:119:13 | [post] access to local variable a : Int32[] [element] : Int32 | semmle.label | [post] access to local variable a : Int32[] [element] : Int32 | | J.cs:119:13:119:13 | [post] access to local variable a : Int32[] [element] : Int32 | semmle.label | [post] access to local variable a : Int32[] [element] : Int32 | | J.cs:119:20:119:34 | call to method Source : Int32 | semmle.label | call to method Source : Int32 | +| J.cs:119:20:119:34 | call to method Source : Int32 | semmle.label | call to method Source : Int32 | +| J.cs:125:14:125:14 | access to local variable a : Int32[] [element] : Int32 | semmle.label | access to local variable a : Int32[] [element] : Int32 | | J.cs:125:14:125:14 | access to local variable a : Int32[] [element] : Int32 | semmle.label | access to local variable a : Int32[] [element] : Int32 | | J.cs:125:14:125:17 | (...) ... | semmle.label | (...) ... | +| J.cs:125:14:125:17 | (...) ... | semmle.label | (...) ... | +| J.cs:125:14:125:17 | access to array element : Int32 | semmle.label | access to array element : Int32 | | J.cs:125:14:125:17 | access to array element : Int32 | semmle.label | access to array element : Int32 | subpaths | A.cs:6:24:6:24 | access to local variable c : C | A.cs:147:32:147:32 | c : C | A.cs:149:20:149:27 | object creation of type B : B [field c] : C | A.cs:6:17:6:25 | call to method Make : B [field c] : C | +| A.cs:6:24:6:24 | access to local variable c : C | A.cs:147:32:147:32 | c : C | A.cs:149:20:149:27 | object creation of type B : B [field c] : C | A.cs:6:17:6:25 | call to method Make : B [field c] : C | +| A.cs:13:15:13:29 | call to method Source : C1 | A.cs:145:27:145:27 | c : C1 | A.cs:145:32:145:35 | [post] this access : B [field c] : C1 | A.cs:13:9:13:9 | [post] access to local variable b : B [field c] : C1 | | A.cs:13:15:13:29 | call to method Source : C1 | A.cs:145:27:145:27 | c : C1 | A.cs:145:32:145:35 | [post] this access : B [field c] : C1 | A.cs:13:9:13:9 | [post] access to local variable b : B [field c] : C1 | | A.cs:14:14:14:14 | access to local variable b : B [field c] : C1 | A.cs:146:18:146:20 | this : B [field c] : C1 | A.cs:146:33:146:38 | access to field c : C1 | A.cs:14:14:14:20 | call to method Get | +| A.cs:14:14:14:14 | access to local variable b : B [field c] : C1 | A.cs:146:18:146:20 | this : B [field c] : C1 | A.cs:146:33:146:38 | access to field c : C1 | A.cs:14:14:14:20 | call to method Get | +| A.cs:15:15:15:35 | object creation of type B : B [field c] : C | A.cs:146:18:146:20 | this : B [field c] : C | A.cs:146:33:146:38 | access to field c : C | A.cs:15:14:15:42 | call to method Get | | A.cs:15:15:15:35 | object creation of type B : B [field c] : C | A.cs:146:18:146:20 | this : B [field c] : C | A.cs:146:33:146:38 | access to field c : C | A.cs:15:14:15:42 | call to method Get | | A.cs:15:21:15:34 | call to method Source : C | A.cs:141:20:141:20 | c : C | A.cs:143:13:143:16 | [post] this access : B [field c] : C | A.cs:15:15:15:35 | object creation of type B : B [field c] : C | +| A.cs:15:21:15:34 | call to method Source : C | A.cs:141:20:141:20 | c : C | A.cs:143:13:143:16 | [post] this access : B [field c] : C | A.cs:15:15:15:35 | object creation of type B : B [field c] : C | +| A.cs:22:25:22:37 | call to method Source : C2 | A.cs:42:29:42:29 | c : C2 | A.cs:48:20:48:21 | access to local variable b2 : B [field c] : C2 | A.cs:22:14:22:38 | call to method SetOnB : B [field c] : C2 | | A.cs:22:25:22:37 | call to method Source : C2 | A.cs:42:29:42:29 | c : C2 | A.cs:48:20:48:21 | access to local variable b2 : B [field c] : C2 | A.cs:22:14:22:38 | call to method SetOnB : B [field c] : C2 | | A.cs:31:29:31:41 | call to method Source : C2 | A.cs:36:33:36:33 | c : C2 | A.cs:39:16:39:28 | ... ? ... : ... : B [field c] : C2 | A.cs:31:14:31:42 | call to method SetOnBWrap : B [field c] : C2 | +| A.cs:31:29:31:41 | call to method Source : C2 | A.cs:36:33:36:33 | c : C2 | A.cs:39:16:39:28 | ... ? ... : ... : B [field c] : C2 | A.cs:31:14:31:42 | call to method SetOnBWrap : B [field c] : C2 | +| A.cs:38:29:38:29 | access to parameter c : C2 | A.cs:42:29:42:29 | c : C2 | A.cs:48:20:48:21 | access to local variable b2 : B [field c] : C2 | A.cs:38:18:38:30 | call to method SetOnB : B [field c] : C2 | | A.cs:38:29:38:29 | access to parameter c : C2 | A.cs:42:29:42:29 | c : C2 | A.cs:48:20:48:21 | access to local variable b2 : B [field c] : C2 | A.cs:38:18:38:30 | call to method SetOnB : B [field c] : C2 | | A.cs:47:20:47:20 | access to parameter c : C2 | A.cs:145:27:145:27 | c : C2 | A.cs:145:32:145:35 | [post] this access : B [field c] : C2 | A.cs:47:13:47:14 | [post] access to local variable b2 : B [field c] : C2 | +| A.cs:47:20:47:20 | access to parameter c : C2 | A.cs:145:27:145:27 | c : C2 | A.cs:145:32:145:35 | [post] this access : B [field c] : C2 | A.cs:47:13:47:14 | [post] access to local variable b2 : B [field c] : C2 | +| A.cs:83:15:83:26 | call to method Source : C | A.cs:145:27:145:27 | c : C | A.cs:145:32:145:35 | [post] this access : B [field c] : C | A.cs:83:9:83:9 | [post] access to parameter b : B [field c] : C | | A.cs:83:15:83:26 | call to method Source : C | A.cs:145:27:145:27 | c : C | A.cs:145:32:145:35 | [post] this access : B [field c] : C | A.cs:83:9:83:9 | [post] access to parameter b : B [field c] : C | | A.cs:105:23:105:23 | access to local variable b : B | A.cs:95:20:95:20 | b : B | A.cs:98:13:98:16 | [post] this access : D [field b] : B | A.cs:105:17:105:29 | object creation of type D : D [field b] : B | +| A.cs:105:23:105:23 | access to local variable b : B | A.cs:95:20:95:20 | b : B | A.cs:98:13:98:16 | [post] this access : D [field b] : B | A.cs:105:17:105:29 | object creation of type D : D [field b] : B | +| A.cs:114:29:114:29 | access to local variable b : B | A.cs:157:25:157:28 | head : B | A.cs:159:13:159:16 | [post] this access : MyList [field head] : B | A.cs:114:18:114:54 | object creation of type MyList : MyList [field head] : B | | A.cs:114:29:114:29 | access to local variable b : B | A.cs:157:25:157:28 | head : B | A.cs:159:13:159:16 | [post] this access : MyList [field head] : B | A.cs:114:18:114:54 | object creation of type MyList : MyList [field head] : B | | A.cs:115:35:115:36 | access to local variable l1 : MyList [field head] : B | A.cs:157:38:157:41 | next : MyList [field head] : B | A.cs:160:13:160:16 | [post] this access : MyList [field next, field head] : B | A.cs:115:18:115:37 | object creation of type MyList : MyList [field next, field head] : B | +| A.cs:115:35:115:36 | access to local variable l1 : MyList [field head] : B | A.cs:157:38:157:41 | next : MyList [field head] : B | A.cs:160:13:160:16 | [post] this access : MyList [field next, field head] : B | A.cs:115:18:115:37 | object creation of type MyList : MyList [field next, field head] : B | +| A.cs:116:35:116:36 | access to local variable l2 : MyList [field next, field head] : B | A.cs:157:38:157:41 | next : MyList [field next, field head] : B | A.cs:160:13:160:16 | [post] this access : MyList [field next, field next, field head] : B | A.cs:116:18:116:37 | object creation of type MyList : MyList [field next, field next, field head] : B | | A.cs:116:35:116:36 | access to local variable l2 : MyList [field next, field head] : B | A.cs:157:38:157:41 | next : MyList [field next, field head] : B | A.cs:160:13:160:16 | [post] this access : MyList [field next, field next, field head] : B | A.cs:116:18:116:37 | object creation of type MyList : MyList [field next, field next, field head] : B | | A.cs:149:26:149:26 | access to parameter c : C | A.cs:141:20:141:20 | c : C | A.cs:143:13:143:16 | [post] this access : B [field c] : C | A.cs:149:20:149:27 | object creation of type B : B [field c] : C | +| A.cs:149:26:149:26 | access to parameter c : C | A.cs:141:20:141:20 | c : C | A.cs:143:13:143:16 | [post] this access : B [field c] : C | A.cs:149:20:149:27 | object creation of type B : B [field c] : C | +| B.cs:6:27:6:27 | access to local variable e : Elem | B.cs:29:26:29:27 | e1 : Elem | B.cs:31:13:31:16 | [post] this access : Box1 [field elem1] : Elem | B.cs:6:18:6:34 | object creation of type Box1 : Box1 [field elem1] : Elem | | B.cs:6:27:6:27 | access to local variable e : Elem | B.cs:29:26:29:27 | e1 : Elem | B.cs:31:13:31:16 | [post] this access : Box1 [field elem1] : Elem | B.cs:6:18:6:34 | object creation of type Box1 : Box1 [field elem1] : Elem | | B.cs:7:27:7:28 | access to local variable b1 : Box1 [field elem1] : Elem | B.cs:39:26:39:27 | b1 : Box1 [field elem1] : Elem | B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem1] : Elem | B.cs:7:18:7:29 | object creation of type Box2 : Box2 [field box1, field elem1] : Elem | +| B.cs:7:27:7:28 | access to local variable b1 : Box1 [field elem1] : Elem | B.cs:39:26:39:27 | b1 : Box1 [field elem1] : Elem | B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem1] : Elem | B.cs:7:18:7:29 | object creation of type Box2 : Box2 [field box1, field elem1] : Elem | +| B.cs:15:33:15:33 | access to local variable e : Elem | B.cs:29:35:29:36 | e2 : Elem | B.cs:32:13:32:16 | [post] this access : Box1 [field elem2] : Elem | B.cs:15:18:15:34 | object creation of type Box1 : Box1 [field elem2] : Elem | | B.cs:15:33:15:33 | access to local variable e : Elem | B.cs:29:35:29:36 | e2 : Elem | B.cs:32:13:32:16 | [post] this access : Box1 [field elem2] : Elem | B.cs:15:18:15:34 | object creation of type Box1 : Box1 [field elem2] : Elem | | B.cs:16:27:16:28 | access to local variable b1 : Box1 [field elem2] : Elem | B.cs:39:26:39:27 | b1 : Box1 [field elem2] : Elem | B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem2] : Elem | B.cs:16:18:16:29 | object creation of type Box2 : Box2 [field box1, field elem2] : Elem | +| B.cs:16:27:16:28 | access to local variable b1 : Box1 [field elem2] : Elem | B.cs:39:26:39:27 | b1 : Box1 [field elem2] : Elem | B.cs:41:13:41:16 | [post] this access : Box2 [field box1, field elem2] : Elem | B.cs:16:18:16:29 | object creation of type Box2 : Box2 [field box1, field elem2] : Elem | +| D.cs:15:34:15:38 | access to parameter value : Object | D.cs:9:9:9:11 | value : Object | D.cs:9:15:9:18 | [post] this access : D [field trivialPropField] : Object | D.cs:15:15:15:18 | [post] this access : D [field trivialPropField] : Object | | D.cs:15:34:15:38 | access to parameter value : Object | D.cs:9:9:9:11 | value : Object | D.cs:9:15:9:18 | [post] this access : D [field trivialPropField] : Object | D.cs:15:15:15:18 | [post] this access : D [field trivialPropField] : Object | | D.cs:22:27:22:28 | access to parameter o2 : Object | D.cs:9:9:9:11 | value : Object | D.cs:9:15:9:18 | [post] this access : D [field trivialPropField] : Object | D.cs:22:9:22:11 | [post] access to local variable ret : D [field trivialPropField] : Object | +| D.cs:22:27:22:28 | access to parameter o2 : Object | D.cs:9:9:9:11 | value : Object | D.cs:9:15:9:18 | [post] this access : D [field trivialPropField] : Object | D.cs:22:9:22:11 | [post] access to local variable ret : D [field trivialPropField] : Object | +| D.cs:23:27:23:28 | access to parameter o3 : Object | D.cs:15:9:15:11 | value : Object | D.cs:15:15:15:18 | [post] this access : D [field trivialPropField] : Object | D.cs:23:9:23:11 | [post] access to local variable ret : D [field trivialPropField] : Object | | D.cs:23:27:23:28 | access to parameter o3 : Object | D.cs:15:9:15:11 | value : Object | D.cs:15:15:15:18 | [post] this access : D [field trivialPropField] : Object | D.cs:23:9:23:11 | [post] access to local variable ret : D [field trivialPropField] : Object | | D.cs:31:24:31:24 | access to local variable o : Object | D.cs:18:28:18:29 | o1 : Object | D.cs:24:16:24:18 | access to local variable ret : D [property AutoProp] : Object | D.cs:31:17:31:37 | call to method Create : D [property AutoProp] : Object | +| D.cs:31:24:31:24 | access to local variable o : Object | D.cs:18:28:18:29 | o1 : Object | D.cs:24:16:24:18 | access to local variable ret : D [property AutoProp] : Object | D.cs:31:17:31:37 | call to method Create : D [property AutoProp] : Object | +| D.cs:37:26:37:42 | call to method Source : Object | D.cs:18:39:18:40 | o2 : Object | D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | | D.cs:37:26:37:42 | call to method Source : Object | D.cs:18:39:18:40 | o2 : Object | D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | D.cs:37:13:37:49 | call to method Create : D [field trivialPropField] : Object | | D.cs:39:14:39:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | D.cs:8:22:8:42 | access to field trivialPropField : Object | D.cs:39:14:39:26 | access to property TrivialProp | +| D.cs:39:14:39:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | D.cs:8:22:8:42 | access to field trivialPropField : Object | D.cs:39:14:39:26 | access to property TrivialProp | +| D.cs:41:14:41:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | D.cs:14:22:14:42 | access to field trivialPropField : Object | D.cs:41:14:41:26 | access to property ComplexProp | | D.cs:41:14:41:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | D.cs:14:22:14:42 | access to field trivialPropField : Object | D.cs:41:14:41:26 | access to property ComplexProp | | D.cs:43:32:43:48 | call to method Source : Object | D.cs:18:50:18:51 | o3 : Object | D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | +| D.cs:43:32:43:48 | call to method Source : Object | D.cs:18:50:18:51 | o3 : Object | D.cs:24:16:24:18 | access to local variable ret : D [field trivialPropField] : Object | D.cs:43:13:43:49 | call to method Create : D [field trivialPropField] : Object | +| D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | D.cs:8:22:8:42 | access to field trivialPropField : Object | D.cs:45:14:45:26 | access to property TrivialProp | | D.cs:45:14:45:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:8:9:8:11 | this : D [field trivialPropField] : Object | D.cs:8:22:8:42 | access to field trivialPropField : Object | D.cs:45:14:45:26 | access to property TrivialProp | | D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | D.cs:14:22:14:42 | access to field trivialPropField : Object | D.cs:47:14:47:26 | access to property ComplexProp | +| D.cs:47:14:47:14 | access to local variable d : D [field trivialPropField] : Object | D.cs:14:9:14:11 | this : D [field trivialPropField] : Object | D.cs:14:22:14:42 | access to field trivialPropField : Object | D.cs:47:14:47:26 | access to property ComplexProp | +| E.cs:23:25:23:25 | access to local variable o : Object | E.cs:8:29:8:29 | o : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object | | E.cs:23:25:23:25 | access to local variable o : Object | E.cs:8:29:8:29 | o : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object | | F.cs:11:24:11:24 | access to local variable o : Object | F.cs:6:28:6:29 | o1 : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field1] : Object | F.cs:11:17:11:31 | call to method Create : F [field Field1] : Object | +| F.cs:11:24:11:24 | access to local variable o : Object | F.cs:6:28:6:29 | o1 : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field1] : Object | F.cs:11:17:11:31 | call to method Create : F [field Field1] : Object | +| F.cs:15:26:15:42 | call to method Source : Object | F.cs:6:39:6:40 | o2 : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field2] : Object | F.cs:15:13:15:43 | call to method Create : F [field Field2] : Object | | F.cs:15:26:15:42 | call to method Source : Object | F.cs:6:39:6:40 | o2 : Object | F.cs:6:46:6:81 | object creation of type F : F [field Field2] : Object | F.cs:15:13:15:43 | call to method Create : F [field Field2] : Object | | G.cs:17:24:17:24 | access to local variable e : Elem | G.cs:64:34:64:34 | e : Elem | G.cs:64:39:64:42 | [post] this access : Box1 [field Elem] : Elem | G.cs:17:9:17:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | +| G.cs:17:24:17:24 | access to local variable e : Elem | G.cs:64:34:64:34 | e : Elem | G.cs:64:39:64:42 | [post] this access : Box1 [field Elem] : Elem | G.cs:17:9:17:14 | [post] access to field Box1 : Box1 [field Elem] : Elem | +| G.cs:33:29:33:29 | access to local variable e : Elem | G.cs:64:34:64:34 | e : Elem | G.cs:64:39:64:42 | [post] this access : Box1 [field Elem] : Elem | G.cs:33:9:33:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | | G.cs:33:29:33:29 | access to local variable e : Elem | G.cs:64:34:64:34 | e : Elem | G.cs:64:39:64:42 | [post] this access : Box1 [field Elem] : Elem | G.cs:33:9:33:19 | [post] call to method GetBox1 : Box1 [field Elem] : Elem | | G.cs:39:14:39:15 | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | G.cs:71:21:71:27 | this : Box2 [field Box1, field Elem] : Elem | G.cs:71:34:71:37 | access to field Box1 : Box1 [field Elem] : Elem | G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | +| G.cs:39:14:39:15 | access to parameter b2 : Box2 [field Box1, field Elem] : Elem | G.cs:71:21:71:27 | this : Box2 [field Box1, field Elem] : Elem | G.cs:71:34:71:37 | access to field Box1 : Box1 [field Elem] : Elem | G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | +| G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | G.cs:63:21:63:27 | this : Box1 [field Elem] : Elem | G.cs:63:34:63:37 | access to field Elem : Elem | G.cs:39:14:39:35 | call to method GetElem | | G.cs:39:14:39:25 | call to method GetBox1 : Box1 [field Elem] : Elem | G.cs:63:21:63:27 | this : Box1 [field Elem] : Elem | G.cs:63:34:63:37 | access to field Elem : Elem | G.cs:39:14:39:35 | call to method GetElem | | H.cs:24:27:24:27 | access to local variable a : A [field FieldA] : Object | H.cs:13:15:13:15 | a : A [field FieldA] : Object | H.cs:17:16:17:18 | access to local variable ret : A [field FieldA] : Object | H.cs:24:21:24:28 | call to method Clone : A [field FieldA] : Object | +| H.cs:24:27:24:27 | access to local variable a : A [field FieldA] : Object | H.cs:13:15:13:15 | a : A [field FieldA] : Object | H.cs:17:16:17:18 | access to local variable ret : A [field FieldA] : Object | H.cs:24:21:24:28 | call to method Clone : A [field FieldA] : Object | +| H.cs:44:27:44:27 | access to local variable a : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : Object | H.cs:44:17:44:28 | call to method Transform : B [field FieldB] : Object | | H.cs:44:27:44:27 | access to local variable a : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : Object | H.cs:44:17:44:28 | call to method Transform : B [field FieldB] : Object | | H.cs:64:22:64:22 | access to local variable a : A [field FieldA] : Object | H.cs:53:25:53:25 | a : A [field FieldA] : Object | H.cs:55:9:55:10 | [post] access to parameter b1 : B [field FieldB] : Object | H.cs:64:25:64:26 | [post] access to local variable b1 : B [field FieldB] : Object | +| H.cs:64:22:64:22 | access to local variable a : A [field FieldA] : Object | H.cs:53:25:53:25 | a : A [field FieldA] : Object | H.cs:55:9:55:10 | [post] access to parameter b1 : B [field FieldB] : Object | H.cs:64:25:64:26 | [post] access to local variable b1 : B [field FieldB] : Object | +| H.cs:80:22:80:22 | access to parameter a : A [field FieldA] : Object | H.cs:53:25:53:25 | a : A [field FieldA] : Object | H.cs:55:9:55:10 | [post] access to parameter b1 : B [field FieldB] : Object | H.cs:80:25:80:26 | [post] access to parameter b1 : B [field FieldB] : Object | | H.cs:80:22:80:22 | access to parameter a : A [field FieldA] : Object | H.cs:53:25:53:25 | a : A [field FieldA] : Object | H.cs:55:9:55:10 | [post] access to parameter b1 : B [field FieldB] : Object | H.cs:80:25:80:26 | [post] access to parameter b1 : B [field FieldB] : Object | | H.cs:88:20:88:36 | call to method Source : Object | H.cs:77:30:77:30 | o : Object | H.cs:79:9:79:9 | [post] access to parameter a : A [field FieldA] : Object | H.cs:88:17:88:17 | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:88:20:88:36 | call to method Source : Object | H.cs:77:30:77:30 | o : Object | H.cs:79:9:79:9 | [post] access to parameter a : A [field FieldA] : Object | H.cs:88:17:88:17 | [post] access to local variable a : A [field FieldA] : Object | +| H.cs:88:20:88:36 | call to method Source : Object | H.cs:77:30:77:30 | o : Object | H.cs:80:25:80:26 | [post] access to parameter b1 : B [field FieldB] : Object | H.cs:88:39:88:40 | [post] access to local variable b1 : B [field FieldB] : Object | | H.cs:88:20:88:36 | call to method Source : Object | H.cs:77:30:77:30 | o : Object | H.cs:80:25:80:26 | [post] access to parameter b1 : B [field FieldB] : Object | H.cs:88:39:88:40 | [post] access to local variable b1 : B [field FieldB] : Object | | H.cs:106:26:106:39 | (...) ... : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : Object | H.cs:106:16:106:40 | call to method Transform : B [field FieldB] : Object | +| H.cs:106:26:106:39 | (...) ... : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : Object | H.cs:106:16:106:40 | call to method Transform : B [field FieldB] : Object | +| H.cs:113:31:113:31 | access to local variable a : A [field FieldA] : Object | H.cs:102:23:102:23 | a : A [field FieldA] : Object | H.cs:106:16:106:40 | call to method Transform : B [field FieldB] : Object | H.cs:113:17:113:32 | call to method TransformWrap : B [field FieldB] : Object | | H.cs:113:31:113:31 | access to local variable a : A [field FieldA] : Object | H.cs:102:23:102:23 | a : A [field FieldA] : Object | H.cs:106:16:106:40 | call to method Transform : B [field FieldB] : Object | H.cs:113:17:113:32 | call to method TransformWrap : B [field FieldB] : Object | | H.cs:124:26:124:26 | access to parameter a : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : Object | H.cs:124:16:124:27 | call to method Transform : B [field FieldB] : Object | +| H.cs:124:26:124:26 | access to parameter a : A [field FieldA] : Object | H.cs:33:19:33:19 | a : A [field FieldA] : Object | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : Object | H.cs:124:16:124:27 | call to method Transform : B [field FieldB] : Object | +| H.cs:131:18:131:18 | access to local variable a : A [field FieldA] : Object | H.cs:122:18:122:18 | a : A [field FieldA] : Object | H.cs:124:16:124:34 | access to field FieldB : Object | H.cs:131:14:131:19 | call to method Get | | H.cs:131:18:131:18 | access to local variable a : A [field FieldA] : Object | H.cs:122:18:122:18 | a : A [field FieldA] : Object | H.cs:124:16:124:34 | access to field FieldB : Object | H.cs:131:14:131:19 | call to method Get | | H.cs:142:26:142:26 | access to local variable a : A [field FieldA] : A | H.cs:33:19:33:19 | a : A [field FieldA] : A | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : A | H.cs:142:16:142:27 | call to method Transform : B [field FieldB] : A | +| H.cs:142:26:142:26 | access to local variable a : A [field FieldA] : A | H.cs:33:19:33:19 | a : A [field FieldA] : A | H.cs:37:16:37:16 | access to local variable b : B [field FieldB] : A | H.cs:142:16:142:27 | call to method Transform : B [field FieldB] : A | +| H.cs:147:25:147:38 | call to method Source : A | H.cs:138:27:138:27 | o : A | H.cs:142:16:142:34 | access to field FieldB : A | H.cs:147:17:147:39 | call to method Through : A | | H.cs:147:25:147:38 | call to method Source : A | H.cs:138:27:138:27 | o : A | H.cs:142:16:142:34 | access to field FieldB : A | H.cs:147:17:147:39 | call to method Through : A | | H.cs:164:22:164:22 | access to local variable o : Object | H.cs:153:32:153:32 | o : Object | H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA, field FieldB] : Object | H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA, field FieldB] : Object | +| H.cs:164:22:164:22 | access to local variable o : Object | H.cs:153:32:153:32 | o : Object | H.cs:157:9:157:9 | [post] access to parameter a : A [field FieldA, field FieldB] : Object | H.cs:164:19:164:19 | [post] access to local variable a : A [field FieldA, field FieldB] : Object | | J.cs:62:29:62:29 | access to local variable o : Object | J.cs:14:26:14:30 | field : Object | J.cs:14:50:14:54 | [post] this access : Struct [field Field] : Object | J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object | +| J.cs:62:29:62:29 | access to local variable o : Object | J.cs:14:26:14:30 | field : Object | J.cs:14:50:14:54 | [post] this access : Struct [field Field] : Object | J.cs:62:18:62:36 | object creation of type Struct : Struct [field Field] : Object | +| J.cs:80:35:80:35 | access to local variable o : Object | J.cs:14:40:14:43 | prop : Object | J.cs:14:57:14:60 | [post] this access : Struct [property Prop] : Object | J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object | | J.cs:80:35:80:35 | access to local variable o : Object | J.cs:14:40:14:43 | prop : Object | J.cs:14:57:14:60 | [post] this access : Struct [property Prop] : Object | J.cs:80:18:80:36 | object creation of type Struct : Struct [property Prop] : Object | #select | A.cs:7:14:7:16 | access to field c | A.cs:5:17:5:28 | call to method Source : C | A.cs:7:14:7:16 | access to field c | $@ | A.cs:5:17:5:28 | call to method Source : C | call to method Source : C | +| A.cs:7:14:7:16 | access to field c | A.cs:5:17:5:28 | call to method Source : C | A.cs:7:14:7:16 | access to field c | $@ | A.cs:5:17:5:28 | call to method Source : C | call to method Source : C | +| A.cs:14:14:14:20 | call to method Get | A.cs:13:15:13:29 | call to method Source : C1 | A.cs:14:14:14:20 | call to method Get | $@ | A.cs:13:15:13:29 | call to method Source : C1 | call to method Source : C1 | | A.cs:14:14:14:20 | call to method Get | A.cs:13:15:13:29 | call to method Source : C1 | A.cs:14:14:14:20 | call to method Get | $@ | A.cs:13:15:13:29 | call to method Source : C1 | call to method Source : C1 | | A.cs:15:14:15:42 | call to method Get | A.cs:15:21:15:34 | call to method Source : C | A.cs:15:14:15:42 | call to method Get | $@ | A.cs:15:21:15:34 | call to method Source : C | call to method Source : C | +| A.cs:15:14:15:42 | call to method Get | A.cs:15:21:15:34 | call to method Source : C | A.cs:15:14:15:42 | call to method Get | $@ | A.cs:15:21:15:34 | call to method Source : C | call to method Source : C | +| A.cs:24:14:24:17 | access to field c | A.cs:22:25:22:37 | call to method Source : C2 | A.cs:24:14:24:17 | access to field c | $@ | A.cs:22:25:22:37 | call to method Source : C2 | call to method Source : C2 | | A.cs:24:14:24:17 | access to field c | A.cs:22:25:22:37 | call to method Source : C2 | A.cs:24:14:24:17 | access to field c | $@ | A.cs:22:25:22:37 | call to method Source : C2 | call to method Source : C2 | | A.cs:33:14:33:17 | access to field c | A.cs:31:29:31:41 | call to method Source : C2 | A.cs:33:14:33:17 | access to field c | $@ | A.cs:31:29:31:41 | call to method Source : C2 | call to method Source : C2 | +| A.cs:33:14:33:17 | access to field c | A.cs:31:29:31:41 | call to method Source : C2 | A.cs:33:14:33:17 | access to field c | $@ | A.cs:31:29:31:41 | call to method Source : C2 | call to method Source : C2 | +| A.cs:64:18:64:26 | access to field a | A.cs:55:17:55:28 | call to method Source : A | A.cs:64:18:64:26 | access to field a | $@ | A.cs:55:17:55:28 | call to method Source : A | call to method Source : A | | A.cs:64:18:64:26 | access to field a | A.cs:55:17:55:28 | call to method Source : A | A.cs:64:18:64:26 | access to field a | $@ | A.cs:55:17:55:28 | call to method Source : A | call to method Source : A | | A.cs:89:14:89:16 | access to field c | A.cs:83:15:83:26 | call to method Source : C | A.cs:89:14:89:16 | access to field c | $@ | A.cs:83:15:83:26 | call to method Source : C | call to method Source : C | +| A.cs:89:14:89:16 | access to field c | A.cs:83:15:83:26 | call to method Source : C | A.cs:89:14:89:16 | access to field c | $@ | A.cs:83:15:83:26 | call to method Source : C | call to method Source : C | +| A.cs:106:14:106:16 | access to field b | A.cs:98:30:98:43 | call to method Source : B | A.cs:106:14:106:16 | access to field b | $@ | A.cs:98:30:98:43 | call to method Source : B | call to method Source : B | | A.cs:106:14:106:16 | access to field b | A.cs:98:30:98:43 | call to method Source : B | A.cs:106:14:106:16 | access to field b | $@ | A.cs:98:30:98:43 | call to method Source : B | call to method Source : B | | A.cs:106:14:106:16 | access to field b | A.cs:104:17:104:30 | call to method Source : B | A.cs:106:14:106:16 | access to field b | $@ | A.cs:104:17:104:30 | call to method Source : B | call to method Source : B | +| A.cs:106:14:106:16 | access to field b | A.cs:104:17:104:30 | call to method Source : B | A.cs:106:14:106:16 | access to field b | $@ | A.cs:104:17:104:30 | call to method Source : B | call to method Source : B | +| A.cs:107:14:107:18 | access to field c | A.cs:97:19:97:32 | call to method Source : C | A.cs:107:14:107:18 | access to field c | $@ | A.cs:97:19:97:32 | call to method Source : C | call to method Source : C | | A.cs:107:14:107:18 | access to field c | A.cs:97:19:97:32 | call to method Source : C | A.cs:107:14:107:18 | access to field c | $@ | A.cs:97:19:97:32 | call to method Source : C | call to method Source : C | | A.cs:108:14:108:16 | access to field c | A.cs:97:19:97:32 | call to method Source : C | A.cs:108:14:108:16 | access to field c | $@ | A.cs:97:19:97:32 | call to method Source : C | call to method Source : C | +| A.cs:108:14:108:16 | access to field c | A.cs:97:19:97:32 | call to method Source : C | A.cs:108:14:108:16 | access to field c | $@ | A.cs:97:19:97:32 | call to method Source : C | call to method Source : C | +| A.cs:119:14:119:30 | access to field head | A.cs:113:17:113:29 | call to method Source : B | A.cs:119:14:119:30 | access to field head | $@ | A.cs:113:17:113:29 | call to method Source : B | call to method Source : B | | A.cs:119:14:119:30 | access to field head | A.cs:113:17:113:29 | call to method Source : B | A.cs:119:14:119:30 | access to field head | $@ | A.cs:113:17:113:29 | call to method Source : B | call to method Source : B | | A.cs:123:18:123:23 | access to field head | A.cs:113:17:113:29 | call to method Source : B | A.cs:123:18:123:23 | access to field head | $@ | A.cs:113:17:113:29 | call to method Source : B | call to method Source : B | +| A.cs:123:18:123:23 | access to field head | A.cs:113:17:113:29 | call to method Source : B | A.cs:123:18:123:23 | access to field head | $@ | A.cs:113:17:113:29 | call to method Source : B | call to method Source : B | +| B.cs:8:14:8:26 | access to field elem1 | B.cs:5:17:5:31 | call to method Source : Elem | B.cs:8:14:8:26 | access to field elem1 | $@ | B.cs:5:17:5:31 | call to method Source : Elem | call to method Source : Elem | | B.cs:8:14:8:26 | access to field elem1 | B.cs:5:17:5:31 | call to method Source : Elem | B.cs:8:14:8:26 | access to field elem1 | $@ | B.cs:5:17:5:31 | call to method Source : Elem | call to method Source : Elem | | B.cs:18:14:18:26 | access to field elem2 | B.cs:14:17:14:31 | call to method Source : Elem | B.cs:18:14:18:26 | access to field elem2 | $@ | B.cs:14:17:14:31 | call to method Source : Elem | call to method Source : Elem | +| B.cs:18:14:18:26 | access to field elem2 | B.cs:14:17:14:31 | call to method Source : Elem | B.cs:18:14:18:26 | access to field elem2 | $@ | B.cs:14:17:14:31 | call to method Source : Elem | call to method Source : Elem | +| C.cs:23:14:23:15 | access to field s1 | C.cs:3:23:3:37 | call to method Source : Elem | C.cs:23:14:23:15 | access to field s1 | $@ | C.cs:3:23:3:37 | call to method Source : Elem | call to method Source : Elem | | C.cs:23:14:23:15 | access to field s1 | C.cs:3:23:3:37 | call to method Source : Elem | C.cs:23:14:23:15 | access to field s1 | $@ | C.cs:3:23:3:37 | call to method Source : Elem | call to method Source : Elem | | C.cs:24:14:24:15 | access to field s2 | C.cs:4:32:4:46 | call to method Source : Elem | C.cs:24:14:24:15 | access to field s2 | $@ | C.cs:4:32:4:46 | call to method Source : Elem | call to method Source : Elem | +| C.cs:24:14:24:15 | access to field s2 | C.cs:4:32:4:46 | call to method Source : Elem | C.cs:24:14:24:15 | access to field s2 | $@ | C.cs:4:32:4:46 | call to method Source : Elem | call to method Source : Elem | +| C.cs:25:14:25:15 | access to field s3 | C.cs:18:19:18:33 | call to method Source : Elem | C.cs:25:14:25:15 | access to field s3 | $@ | C.cs:18:19:18:33 | call to method Source : Elem | call to method Source : Elem | | C.cs:25:14:25:15 | access to field s3 | C.cs:18:19:18:33 | call to method Source : Elem | C.cs:25:14:25:15 | access to field s3 | $@ | C.cs:18:19:18:33 | call to method Source : Elem | call to method Source : Elem | | C.cs:26:14:26:15 | access to field s4 | C.cs:6:30:6:44 | call to method Source : Elem | C.cs:26:14:26:15 | access to field s4 | $@ | C.cs:6:30:6:44 | call to method Source : Elem | call to method Source : Elem | +| C.cs:26:14:26:15 | access to field s4 | C.cs:6:30:6:44 | call to method Source : Elem | C.cs:26:14:26:15 | access to field s4 | $@ | C.cs:6:30:6:44 | call to method Source : Elem | call to method Source : Elem | +| C.cs:27:14:27:15 | access to property s5 | C.cs:7:37:7:51 | call to method Source : Elem | C.cs:27:14:27:15 | access to property s5 | $@ | C.cs:7:37:7:51 | call to method Source : Elem | call to method Source : Elem | | C.cs:27:14:27:15 | access to property s5 | C.cs:7:37:7:51 | call to method Source : Elem | C.cs:27:14:27:15 | access to property s5 | $@ | C.cs:7:37:7:51 | call to method Source : Elem | call to method Source : Elem | | C.cs:28:14:28:15 | access to property s6 | C.cs:8:30:8:44 | call to method Source : Elem | C.cs:28:14:28:15 | access to property s6 | $@ | C.cs:8:30:8:44 | call to method Source : Elem | call to method Source : Elem | +| C.cs:28:14:28:15 | access to property s6 | C.cs:8:30:8:44 | call to method Source : Elem | C.cs:28:14:28:15 | access to property s6 | $@ | C.cs:8:30:8:44 | call to method Source : Elem | call to method Source : Elem | +| C_ctor.cs:13:19:13:20 | access to field s1 | C_ctor.cs:3:23:3:42 | call to method Source : Elem | C_ctor.cs:13:19:13:20 | access to field s1 | $@ | C_ctor.cs:3:23:3:42 | call to method Source : Elem | call to method Source : Elem | | C_ctor.cs:13:19:13:20 | access to field s1 | C_ctor.cs:3:23:3:42 | call to method Source : Elem | C_ctor.cs:13:19:13:20 | access to field s1 | $@ | C_ctor.cs:3:23:3:42 | call to method Source : Elem | call to method Source : Elem | | C_ctor.cs:31:19:31:20 | access to field s1 | C_ctor.cs:19:23:19:42 | call to method Source : Elem | C_ctor.cs:31:19:31:20 | access to field s1 | $@ | C_ctor.cs:19:23:19:42 | call to method Source : Elem | call to method Source : Elem | +| C_ctor.cs:31:19:31:20 | access to field s1 | C_ctor.cs:19:23:19:42 | call to method Source : Elem | C_ctor.cs:31:19:31:20 | access to field s1 | $@ | C_ctor.cs:19:23:19:42 | call to method Source : Elem | call to method Source : Elem | +| D.cs:32:14:32:23 | access to property AutoProp | D.cs:29:17:29:33 | call to method Source : Object | D.cs:32:14:32:23 | access to property AutoProp | $@ | D.cs:29:17:29:33 | call to method Source : Object | call to method Source : Object | | D.cs:32:14:32:23 | access to property AutoProp | D.cs:29:17:29:33 | call to method Source : Object | D.cs:32:14:32:23 | access to property AutoProp | $@ | D.cs:29:17:29:33 | call to method Source : Object | call to method Source : Object | | D.cs:39:14:39:26 | access to property TrivialProp | D.cs:37:26:37:42 | call to method Source : Object | D.cs:39:14:39:26 | access to property TrivialProp | $@ | D.cs:37:26:37:42 | call to method Source : Object | call to method Source : Object | +| D.cs:39:14:39:26 | access to property TrivialProp | D.cs:37:26:37:42 | call to method Source : Object | D.cs:39:14:39:26 | access to property TrivialProp | $@ | D.cs:37:26:37:42 | call to method Source : Object | call to method Source : Object | +| D.cs:40:14:40:31 | access to field trivialPropField | D.cs:37:26:37:42 | call to method Source : Object | D.cs:40:14:40:31 | access to field trivialPropField | $@ | D.cs:37:26:37:42 | call to method Source : Object | call to method Source : Object | | D.cs:40:14:40:31 | access to field trivialPropField | D.cs:37:26:37:42 | call to method Source : Object | D.cs:40:14:40:31 | access to field trivialPropField | $@ | D.cs:37:26:37:42 | call to method Source : Object | call to method Source : Object | | D.cs:41:14:41:26 | access to property ComplexProp | D.cs:37:26:37:42 | call to method Source : Object | D.cs:41:14:41:26 | access to property ComplexProp | $@ | D.cs:37:26:37:42 | call to method Source : Object | call to method Source : Object | +| D.cs:41:14:41:26 | access to property ComplexProp | D.cs:37:26:37:42 | call to method Source : Object | D.cs:41:14:41:26 | access to property ComplexProp | $@ | D.cs:37:26:37:42 | call to method Source : Object | call to method Source : Object | +| D.cs:45:14:45:26 | access to property TrivialProp | D.cs:43:32:43:48 | call to method Source : Object | D.cs:45:14:45:26 | access to property TrivialProp | $@ | D.cs:43:32:43:48 | call to method Source : Object | call to method Source : Object | | D.cs:45:14:45:26 | access to property TrivialProp | D.cs:43:32:43:48 | call to method Source : Object | D.cs:45:14:45:26 | access to property TrivialProp | $@ | D.cs:43:32:43:48 | call to method Source : Object | call to method Source : Object | | D.cs:46:14:46:31 | access to field trivialPropField | D.cs:43:32:43:48 | call to method Source : Object | D.cs:46:14:46:31 | access to field trivialPropField | $@ | D.cs:43:32:43:48 | call to method Source : Object | call to method Source : Object | +| D.cs:46:14:46:31 | access to field trivialPropField | D.cs:43:32:43:48 | call to method Source : Object | D.cs:46:14:46:31 | access to field trivialPropField | $@ | D.cs:43:32:43:48 | call to method Source : Object | call to method Source : Object | +| D.cs:47:14:47:26 | access to property ComplexProp | D.cs:43:32:43:48 | call to method Source : Object | D.cs:47:14:47:26 | access to property ComplexProp | $@ | D.cs:43:32:43:48 | call to method Source : Object | call to method Source : Object | | D.cs:47:14:47:26 | access to property ComplexProp | D.cs:43:32:43:48 | call to method Source : Object | D.cs:47:14:47:26 | access to property ComplexProp | $@ | D.cs:43:32:43:48 | call to method Source : Object | call to method Source : Object | | E.cs:24:14:24:20 | access to field Field | E.cs:22:17:22:33 | call to method Source : Object | E.cs:24:14:24:20 | access to field Field | $@ | E.cs:22:17:22:33 | call to method Source : Object | call to method Source : Object | +| E.cs:24:14:24:20 | access to field Field | E.cs:22:17:22:33 | call to method Source : Object | E.cs:24:14:24:20 | access to field Field | $@ | E.cs:22:17:22:33 | call to method Source : Object | call to method Source : Object | +| F.cs:12:14:12:21 | access to field Field1 | F.cs:10:17:10:33 | call to method Source : Object | F.cs:12:14:12:21 | access to field Field1 | $@ | F.cs:10:17:10:33 | call to method Source : Object | call to method Source : Object | | F.cs:12:14:12:21 | access to field Field1 | F.cs:10:17:10:33 | call to method Source : Object | F.cs:12:14:12:21 | access to field Field1 | $@ | F.cs:10:17:10:33 | call to method Source : Object | call to method Source : Object | | F.cs:17:14:17:21 | access to field Field2 | F.cs:15:26:15:42 | call to method Source : Object | F.cs:17:14:17:21 | access to field Field2 | $@ | F.cs:15:26:15:42 | call to method Source : Object | call to method Source : Object | +| F.cs:17:14:17:21 | access to field Field2 | F.cs:15:26:15:42 | call to method Source : Object | F.cs:17:14:17:21 | access to field Field2 | $@ | F.cs:15:26:15:42 | call to method Source : Object | call to method Source : Object | +| F.cs:20:14:20:21 | access to field Field1 | F.cs:19:32:19:48 | call to method Source : Object | F.cs:20:14:20:21 | access to field Field1 | $@ | F.cs:19:32:19:48 | call to method Source : Object | call to method Source : Object | | F.cs:20:14:20:21 | access to field Field1 | F.cs:19:32:19:48 | call to method Source : Object | F.cs:20:14:20:21 | access to field Field1 | $@ | F.cs:19:32:19:48 | call to method Source : Object | call to method Source : Object | | F.cs:25:14:25:21 | access to field Field2 | F.cs:23:32:23:48 | call to method Source : Object | F.cs:25:14:25:21 | access to field Field2 | $@ | F.cs:23:32:23:48 | call to method Source : Object | call to method Source : Object | +| F.cs:25:14:25:21 | access to field Field2 | F.cs:23:32:23:48 | call to method Source : Object | F.cs:25:14:25:21 | access to field Field2 | $@ | F.cs:23:32:23:48 | call to method Source : Object | call to method Source : Object | +| F.cs:33:14:33:16 | access to property X | F.cs:30:17:30:33 | call to method Source : Object | F.cs:33:14:33:16 | access to property X | $@ | F.cs:30:17:30:33 | call to method Source : Object | call to method Source : Object | | F.cs:33:14:33:16 | access to property X | F.cs:30:17:30:33 | call to method Source : Object | F.cs:33:14:33:16 | access to property X | $@ | F.cs:30:17:30:33 | call to method Source : Object | call to method Source : Object | | G.cs:39:14:39:35 | call to method GetElem | G.cs:7:18:7:32 | call to method Source : Elem | G.cs:39:14:39:35 | call to method GetElem | $@ | G.cs:7:18:7:32 | call to method Source : Elem | call to method Source : Elem | +| G.cs:39:14:39:35 | call to method GetElem | G.cs:7:18:7:32 | call to method Source : Elem | G.cs:39:14:39:35 | call to method GetElem | $@ | G.cs:7:18:7:32 | call to method Source : Elem | call to method Source : Elem | +| G.cs:39:14:39:35 | call to method GetElem | G.cs:15:18:15:32 | call to method Source : Elem | G.cs:39:14:39:35 | call to method GetElem | $@ | G.cs:15:18:15:32 | call to method Source : Elem | call to method Source : Elem | | G.cs:39:14:39:35 | call to method GetElem | G.cs:15:18:15:32 | call to method Source : Elem | G.cs:39:14:39:35 | call to method GetElem | $@ | G.cs:15:18:15:32 | call to method Source : Elem | call to method Source : Elem | | G.cs:39:14:39:35 | call to method GetElem | G.cs:23:18:23:32 | call to method Source : Elem | G.cs:39:14:39:35 | call to method GetElem | $@ | G.cs:23:18:23:32 | call to method Source : Elem | call to method Source : Elem | +| G.cs:39:14:39:35 | call to method GetElem | G.cs:23:18:23:32 | call to method Source : Elem | G.cs:39:14:39:35 | call to method GetElem | $@ | G.cs:23:18:23:32 | call to method Source : Elem | call to method Source : Elem | +| G.cs:39:14:39:35 | call to method GetElem | G.cs:31:18:31:32 | call to method Source : Elem | G.cs:39:14:39:35 | call to method GetElem | $@ | G.cs:31:18:31:32 | call to method Source : Elem | call to method Source : Elem | | G.cs:39:14:39:35 | call to method GetElem | G.cs:31:18:31:32 | call to method Source : Elem | G.cs:39:14:39:35 | call to method GetElem | $@ | G.cs:31:18:31:32 | call to method Source : Elem | call to method Source : Elem | | G.cs:52:14:52:31 | access to field Elem | G.cs:44:18:44:32 | call to method Source : Elem | G.cs:52:14:52:31 | access to field Elem | $@ | G.cs:44:18:44:32 | call to method Source : Elem | call to method Source : Elem | +| G.cs:52:14:52:31 | access to field Elem | G.cs:44:18:44:32 | call to method Source : Elem | G.cs:52:14:52:31 | access to field Elem | $@ | G.cs:44:18:44:32 | call to method Source : Elem | call to method Source : Elem | +| H.cs:25:14:25:25 | access to field FieldA | H.cs:23:20:23:36 | call to method Source : Object | H.cs:25:14:25:25 | access to field FieldA | $@ | H.cs:23:20:23:36 | call to method Source : Object | call to method Source : Object | | H.cs:25:14:25:25 | access to field FieldA | H.cs:23:20:23:36 | call to method Source : Object | H.cs:25:14:25:25 | access to field FieldA | $@ | H.cs:23:20:23:36 | call to method Source : Object | call to method Source : Object | | H.cs:45:14:45:21 | access to field FieldB | H.cs:43:20:43:36 | call to method Source : Object | H.cs:45:14:45:21 | access to field FieldB | $@ | H.cs:43:20:43:36 | call to method Source : Object | call to method Source : Object | +| H.cs:45:14:45:21 | access to field FieldB | H.cs:43:20:43:36 | call to method Source : Object | H.cs:45:14:45:21 | access to field FieldB | $@ | H.cs:43:20:43:36 | call to method Source : Object | call to method Source : Object | +| H.cs:65:14:65:22 | access to field FieldB | H.cs:63:20:63:36 | call to method Source : Object | H.cs:65:14:65:22 | access to field FieldB | $@ | H.cs:63:20:63:36 | call to method Source : Object | call to method Source : Object | | H.cs:65:14:65:22 | access to field FieldB | H.cs:63:20:63:36 | call to method Source : Object | H.cs:65:14:65:22 | access to field FieldB | $@ | H.cs:63:20:63:36 | call to method Source : Object | call to method Source : Object | | H.cs:89:14:89:21 | access to field FieldA | H.cs:88:20:88:36 | call to method Source : Object | H.cs:89:14:89:21 | access to field FieldA | $@ | H.cs:88:20:88:36 | call to method Source : Object | call to method Source : Object | +| H.cs:89:14:89:21 | access to field FieldA | H.cs:88:20:88:36 | call to method Source : Object | H.cs:89:14:89:21 | access to field FieldA | $@ | H.cs:88:20:88:36 | call to method Source : Object | call to method Source : Object | +| H.cs:90:14:90:22 | access to field FieldB | H.cs:88:20:88:36 | call to method Source : Object | H.cs:90:14:90:22 | access to field FieldB | $@ | H.cs:88:20:88:36 | call to method Source : Object | call to method Source : Object | | H.cs:90:14:90:22 | access to field FieldB | H.cs:88:20:88:36 | call to method Source : Object | H.cs:90:14:90:22 | access to field FieldB | $@ | H.cs:88:20:88:36 | call to method Source : Object | call to method Source : Object | | H.cs:114:14:114:21 | access to field FieldB | H.cs:112:20:112:36 | call to method Source : Object | H.cs:114:14:114:21 | access to field FieldB | $@ | H.cs:112:20:112:36 | call to method Source : Object | call to method Source : Object | +| H.cs:114:14:114:21 | access to field FieldB | H.cs:112:20:112:36 | call to method Source : Object | H.cs:114:14:114:21 | access to field FieldB | $@ | H.cs:112:20:112:36 | call to method Source : Object | call to method Source : Object | +| H.cs:131:14:131:19 | call to method Get | H.cs:130:20:130:36 | call to method Source : Object | H.cs:131:14:131:19 | call to method Get | $@ | H.cs:130:20:130:36 | call to method Source : Object | call to method Source : Object | | H.cs:131:14:131:19 | call to method Get | H.cs:130:20:130:36 | call to method Source : Object | H.cs:131:14:131:19 | call to method Get | $@ | H.cs:130:20:130:36 | call to method Source : Object | call to method Source : Object | | H.cs:148:14:148:14 | access to local variable a | H.cs:147:25:147:38 | call to method Source : A | H.cs:148:14:148:14 | access to local variable a | $@ | H.cs:147:25:147:38 | call to method Source : A | call to method Source : A | +| H.cs:148:14:148:14 | access to local variable a | H.cs:147:25:147:38 | call to method Source : A | H.cs:148:14:148:14 | access to local variable a | $@ | H.cs:147:25:147:38 | call to method Source : A | call to method Source : A | +| H.cs:166:14:166:14 | access to local variable b | H.cs:155:17:155:30 | call to method Source : B | H.cs:166:14:166:14 | access to local variable b | $@ | H.cs:155:17:155:30 | call to method Source : B | call to method Source : B | | H.cs:166:14:166:14 | access to local variable b | H.cs:155:17:155:30 | call to method Source : B | H.cs:166:14:166:14 | access to local variable b | $@ | H.cs:155:17:155:30 | call to method Source : B | call to method Source : B | | H.cs:167:14:167:21 | access to field FieldB | H.cs:163:17:163:35 | call to method Source : Object | H.cs:167:14:167:21 | access to field FieldB | $@ | H.cs:163:17:163:35 | call to method Source : Object | call to method Source : Object | +| H.cs:167:14:167:21 | access to field FieldB | H.cs:163:17:163:35 | call to method Source : Object | H.cs:167:14:167:21 | access to field FieldB | $@ | H.cs:163:17:163:35 | call to method Source : Object | call to method Source : Object | +| I.cs:18:14:18:21 | access to field Field1 | I.cs:13:17:13:33 | call to method Source : Object | I.cs:18:14:18:21 | access to field Field1 | $@ | I.cs:13:17:13:33 | call to method Source : Object | call to method Source : Object | | I.cs:18:14:18:21 | access to field Field1 | I.cs:13:17:13:33 | call to method Source : Object | I.cs:18:14:18:21 | access to field Field1 | $@ | I.cs:13:17:13:33 | call to method Source : Object | call to method Source : Object | | I.cs:23:14:23:21 | access to field Field1 | I.cs:7:18:7:34 | call to method Source : Object | I.cs:23:14:23:21 | access to field Field1 | $@ | I.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | +| I.cs:23:14:23:21 | access to field Field1 | I.cs:7:18:7:34 | call to method Source : Object | I.cs:23:14:23:21 | access to field Field1 | $@ | I.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | +| I.cs:27:14:27:21 | access to field Field1 | I.cs:7:18:7:34 | call to method Source : Object | I.cs:27:14:27:21 | access to field Field1 | $@ | I.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | | I.cs:27:14:27:21 | access to field Field1 | I.cs:7:18:7:34 | call to method Source : Object | I.cs:27:14:27:21 | access to field Field1 | $@ | I.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | | I.cs:40:14:40:21 | access to field Field1 | I.cs:31:13:31:29 | call to method Source : Object | I.cs:40:14:40:21 | access to field Field1 | $@ | I.cs:31:13:31:29 | call to method Source : Object | call to method Source : Object | +| I.cs:40:14:40:21 | access to field Field1 | I.cs:31:13:31:29 | call to method Source : Object | I.cs:40:14:40:21 | access to field Field1 | $@ | I.cs:31:13:31:29 | call to method Source : Object | call to method Source : Object | +| J.cs:23:14:23:21 | access to property Prop1 | J.cs:21:17:21:33 | call to method Source : Object | J.cs:23:14:23:21 | access to property Prop1 | $@ | J.cs:21:17:21:33 | call to method Source : Object | call to method Source : Object | | J.cs:23:14:23:21 | access to property Prop1 | J.cs:21:17:21:33 | call to method Source : Object | J.cs:23:14:23:21 | access to property Prop1 | $@ | J.cs:21:17:21:33 | call to method Source : Object | call to method Source : Object | | J.cs:27:14:27:21 | access to property Prop1 | J.cs:21:17:21:33 | call to method Source : Object | J.cs:27:14:27:21 | access to property Prop1 | $@ | J.cs:21:17:21:33 | call to method Source : Object | call to method Source : Object | +| J.cs:27:14:27:21 | access to property Prop1 | J.cs:21:17:21:33 | call to method Source : Object | J.cs:27:14:27:21 | access to property Prop1 | $@ | J.cs:21:17:21:33 | call to method Source : Object | call to method Source : Object | +| J.cs:31:14:31:21 | access to property Prop1 | J.cs:21:17:21:33 | call to method Source : Object | J.cs:31:14:31:21 | access to property Prop1 | $@ | J.cs:21:17:21:33 | call to method Source : Object | call to method Source : Object | | J.cs:31:14:31:21 | access to property Prop1 | J.cs:21:17:21:33 | call to method Source : Object | J.cs:31:14:31:21 | access to property Prop1 | $@ | J.cs:21:17:21:33 | call to method Source : Object | call to method Source : Object | | J.cs:32:14:32:21 | access to property Prop2 | J.cs:30:36:30:52 | call to method Source : Object | J.cs:32:14:32:21 | access to property Prop2 | $@ | J.cs:30:36:30:52 | call to method Source : Object | call to method Source : Object | +| J.cs:32:14:32:21 | access to property Prop2 | J.cs:30:36:30:52 | call to method Source : Object | J.cs:32:14:32:21 | access to property Prop2 | $@ | J.cs:30:36:30:52 | call to method Source : Object | call to method Source : Object | +| J.cs:43:14:43:21 | access to property Prop1 | J.cs:41:17:41:33 | call to method Source : Object | J.cs:43:14:43:21 | access to property Prop1 | $@ | J.cs:41:17:41:33 | call to method Source : Object | call to method Source : Object | | J.cs:43:14:43:21 | access to property Prop1 | J.cs:41:17:41:33 | call to method Source : Object | J.cs:43:14:43:21 | access to property Prop1 | $@ | J.cs:41:17:41:33 | call to method Source : Object | call to method Source : Object | | J.cs:47:14:47:21 | access to property Prop1 | J.cs:41:17:41:33 | call to method Source : Object | J.cs:47:14:47:21 | access to property Prop1 | $@ | J.cs:41:17:41:33 | call to method Source : Object | call to method Source : Object | +| J.cs:47:14:47:21 | access to property Prop1 | J.cs:41:17:41:33 | call to method Source : Object | J.cs:47:14:47:21 | access to property Prop1 | $@ | J.cs:41:17:41:33 | call to method Source : Object | call to method Source : Object | +| J.cs:51:14:51:21 | access to property Prop1 | J.cs:41:17:41:33 | call to method Source : Object | J.cs:51:14:51:21 | access to property Prop1 | $@ | J.cs:41:17:41:33 | call to method Source : Object | call to method Source : Object | | J.cs:51:14:51:21 | access to property Prop1 | J.cs:41:17:41:33 | call to method Source : Object | J.cs:51:14:51:21 | access to property Prop1 | $@ | J.cs:41:17:41:33 | call to method Source : Object | call to method Source : Object | | J.cs:52:14:52:21 | access to property Prop2 | J.cs:50:36:50:52 | call to method Source : Object | J.cs:52:14:52:21 | access to property Prop2 | $@ | J.cs:50:36:50:52 | call to method Source : Object | call to method Source : Object | +| J.cs:52:14:52:21 | access to property Prop2 | J.cs:50:36:50:52 | call to method Source : Object | J.cs:52:14:52:21 | access to property Prop2 | $@ | J.cs:50:36:50:52 | call to method Source : Object | call to method Source : Object | +| J.cs:65:14:65:21 | access to field Field | J.cs:61:17:61:33 | call to method Source : Object | J.cs:65:14:65:21 | access to field Field | $@ | J.cs:61:17:61:33 | call to method Source : Object | call to method Source : Object | | J.cs:65:14:65:21 | access to field Field | J.cs:61:17:61:33 | call to method Source : Object | J.cs:65:14:65:21 | access to field Field | $@ | J.cs:61:17:61:33 | call to method Source : Object | call to method Source : Object | | J.cs:69:14:69:21 | access to field Field | J.cs:61:17:61:33 | call to method Source : Object | J.cs:69:14:69:21 | access to field Field | $@ | J.cs:61:17:61:33 | call to method Source : Object | call to method Source : Object | +| J.cs:69:14:69:21 | access to field Field | J.cs:61:17:61:33 | call to method Source : Object | J.cs:69:14:69:21 | access to field Field | $@ | J.cs:61:17:61:33 | call to method Source : Object | call to method Source : Object | +| J.cs:70:14:70:20 | access to property Prop | J.cs:68:35:68:51 | call to method Source : Object | J.cs:70:14:70:20 | access to property Prop | $@ | J.cs:68:35:68:51 | call to method Source : Object | call to method Source : Object | | J.cs:70:14:70:20 | access to property Prop | J.cs:68:35:68:51 | call to method Source : Object | J.cs:70:14:70:20 | access to property Prop | $@ | J.cs:68:35:68:51 | call to method Source : Object | call to method Source : Object | | J.cs:84:14:84:20 | access to property Prop | J.cs:79:17:79:33 | call to method Source : Object | J.cs:84:14:84:20 | access to property Prop | $@ | J.cs:79:17:79:33 | call to method Source : Object | call to method Source : Object | +| J.cs:84:14:84:20 | access to property Prop | J.cs:79:17:79:33 | call to method Source : Object | J.cs:84:14:84:20 | access to property Prop | $@ | J.cs:79:17:79:33 | call to method Source : Object | call to method Source : Object | +| J.cs:87:14:87:21 | access to field Field | J.cs:86:36:86:52 | call to method Source : Object | J.cs:87:14:87:21 | access to field Field | $@ | J.cs:86:36:86:52 | call to method Source : Object | call to method Source : Object | | J.cs:87:14:87:21 | access to field Field | J.cs:86:36:86:52 | call to method Source : Object | J.cs:87:14:87:21 | access to field Field | $@ | J.cs:86:36:86:52 | call to method Source : Object | call to method Source : Object | | J.cs:88:14:88:20 | access to property Prop | J.cs:79:17:79:33 | call to method Source : Object | J.cs:88:14:88:20 | access to property Prop | $@ | J.cs:79:17:79:33 | call to method Source : Object | call to method Source : Object | +| J.cs:88:14:88:20 | access to property Prop | J.cs:79:17:79:33 | call to method Source : Object | J.cs:88:14:88:20 | access to property Prop | $@ | J.cs:79:17:79:33 | call to method Source : Object | call to method Source : Object | +| J.cs:102:14:102:17 | access to property X | J.cs:97:17:97:33 | call to method Source : Object | J.cs:102:14:102:17 | access to property X | $@ | J.cs:97:17:97:33 | call to method Source : Object | call to method Source : Object | | J.cs:102:14:102:17 | access to property X | J.cs:97:17:97:33 | call to method Source : Object | J.cs:102:14:102:17 | access to property X | $@ | J.cs:97:17:97:33 | call to method Source : Object | call to method Source : Object | | J.cs:106:14:106:17 | access to property X | J.cs:97:17:97:33 | call to method Source : Object | J.cs:106:14:106:17 | access to property X | $@ | J.cs:97:17:97:33 | call to method Source : Object | call to method Source : Object | +| J.cs:106:14:106:17 | access to property X | J.cs:97:17:97:33 | call to method Source : Object | J.cs:106:14:106:17 | access to property X | $@ | J.cs:97:17:97:33 | call to method Source : Object | call to method Source : Object | +| J.cs:107:14:107:17 | access to property Y | J.cs:105:32:105:48 | call to method Source : Object | J.cs:107:14:107:17 | access to property Y | $@ | J.cs:105:32:105:48 | call to method Source : Object | call to method Source : Object | | J.cs:107:14:107:17 | access to property Y | J.cs:105:32:105:48 | call to method Source : Object | J.cs:107:14:107:17 | access to property Y | $@ | J.cs:105:32:105:48 | call to method Source : Object | call to method Source : Object | | J.cs:125:14:125:17 | (...) ... | J.cs:119:20:119:34 | call to method Source : Int32 | J.cs:125:14:125:17 | (...) ... | $@ | J.cs:119:20:119:34 | call to method Source : Int32 | call to method Source : Int32 | +| J.cs:125:14:125:17 | (...) ... | J.cs:119:20:119:34 | call to method Source : Int32 | J.cs:125:14:125:17 | (...) ... | $@ | J.cs:119:20:119:34 | call to method Source : Int32 | call to method Source : Int32 | diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.ql b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.ql index 39395ad831b..9336e1b28be 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.ql @@ -5,8 +5,8 @@ import csharp import TestUtilities.InlineFlowTest import DefaultFlowTest -import ValueFlow::PathGraph +import PathGraph -from ValueFlow::PathNode source, ValueFlow::PathNode sink -where ValueFlow::flowPath(source, sink) +from PathNode source, PathNode sink +where flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected index 3f4f02ff6a1..2bddf573b6a 100644 --- a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected @@ -2,95 +2,185 @@ failures testFailures edges | Operator.cs:9:39:9:39 | x : C | Operator.cs:9:50:9:50 | access to parameter x : C | +| Operator.cs:9:39:9:39 | x : C | Operator.cs:9:50:9:50 | access to parameter x : C | +| Operator.cs:16:38:16:38 | x : C | Operator.cs:16:49:16:49 | access to parameter x : C | | Operator.cs:16:38:16:38 | x : C | Operator.cs:16:49:16:49 | access to parameter x : C | | Operator.cs:18:51:18:51 | y : C | Operator.cs:18:57:18:57 | access to parameter y : C | +| Operator.cs:18:51:18:51 | y : C | Operator.cs:18:57:18:57 | access to parameter y : C | +| Operator.cs:19:38:19:38 | x : C | Operator.cs:19:49:19:49 | access to parameter x : C | | Operator.cs:19:38:19:38 | x : C | Operator.cs:19:49:19:49 | access to parameter x : C | | Operator.cs:21:43:21:43 | y : C | Operator.cs:21:49:21:49 | access to parameter y : C | +| Operator.cs:21:43:21:43 | y : C | Operator.cs:21:49:21:49 | access to parameter y : C | +| Operator.cs:22:51:22:51 | y : C | Operator.cs:22:57:22:57 | access to parameter y : C | | Operator.cs:22:51:22:51 | y : C | Operator.cs:22:57:22:57 | access to parameter y : C | | Operator.cs:27:17:27:28 | call to method Source : C | Operator.cs:29:17:29:17 | access to local variable x : C | +| Operator.cs:27:17:27:28 | call to method Source : C | Operator.cs:29:17:29:17 | access to local variable x : C | +| Operator.cs:29:17:29:17 | access to local variable x : C | Operator.cs:16:38:16:38 | x : C | | Operator.cs:29:17:29:17 | access to local variable x : C | Operator.cs:16:38:16:38 | x : C | | Operator.cs:29:17:29:17 | access to local variable x : C | Operator.cs:29:17:29:21 | call to operator + : C | +| Operator.cs:29:17:29:17 | access to local variable x : C | Operator.cs:29:17:29:21 | call to operator + : C | +| Operator.cs:29:17:29:21 | call to operator + : C | Operator.cs:30:14:30:14 | access to local variable z | | Operator.cs:29:17:29:21 | call to operator + : C | Operator.cs:30:14:30:14 | access to local variable z | | Operator.cs:35:17:35:28 | call to method Source : C | Operator.cs:37:27:37:27 | access to local variable x : C | +| Operator.cs:35:17:35:28 | call to method Source : C | Operator.cs:37:27:37:27 | access to local variable x : C | +| Operator.cs:37:27:37:27 | access to local variable x : C | Operator.cs:19:38:19:38 | x : C | | Operator.cs:37:27:37:27 | access to local variable x : C | Operator.cs:19:38:19:38 | x : C | | Operator.cs:37:27:37:27 | access to local variable x : C | Operator.cs:37:27:37:31 | call to operator - : C | +| Operator.cs:37:27:37:27 | access to local variable x : C | Operator.cs:37:27:37:31 | call to operator - : C | +| Operator.cs:37:27:37:31 | call to operator - : C | Operator.cs:38:14:38:14 | access to local variable z | | Operator.cs:37:27:37:31 | call to operator - : C | Operator.cs:38:14:38:14 | access to local variable z | | Operator.cs:44:17:44:28 | call to method Source : C | Operator.cs:45:29:45:29 | access to local variable y : C | +| Operator.cs:44:17:44:28 | call to method Source : C | Operator.cs:45:29:45:29 | access to local variable y : C | +| Operator.cs:45:25:45:29 | call to operator checked - : C | Operator.cs:46:14:46:14 | access to local variable z | | Operator.cs:45:25:45:29 | call to operator checked - : C | Operator.cs:46:14:46:14 | access to local variable z | | Operator.cs:45:29:45:29 | access to local variable y : C | Operator.cs:18:51:18:51 | y : C | +| Operator.cs:45:29:45:29 | access to local variable y : C | Operator.cs:18:51:18:51 | y : C | +| Operator.cs:45:29:45:29 | access to local variable y : C | Operator.cs:45:25:45:29 | call to operator checked - : C | | Operator.cs:45:29:45:29 | access to local variable y : C | Operator.cs:45:25:45:29 | call to operator checked - : C | | Operator.cs:49:28:49:28 | x : C | Operator.cs:51:17:51:17 | access to parameter x : C | +| Operator.cs:49:28:49:28 | x : C | Operator.cs:51:17:51:17 | access to parameter x : C | +| Operator.cs:51:17:51:17 | access to parameter x : C | Operator.cs:9:39:9:39 | x : C | | Operator.cs:51:17:51:17 | access to parameter x : C | Operator.cs:9:39:9:39 | x : C | | Operator.cs:51:17:51:17 | access to parameter x : C | Operator.cs:51:17:51:21 | call to operator * : C | +| Operator.cs:51:17:51:17 | access to parameter x : C | Operator.cs:51:17:51:21 | call to operator * : C | +| Operator.cs:51:17:51:21 | call to operator * : C | Operator.cs:52:14:52:14 | (...) ... | | Operator.cs:51:17:51:21 | call to operator * : C | Operator.cs:52:14:52:14 | (...) ... | | Operator.cs:57:17:57:28 | call to method Source : C | Operator.cs:59:15:59:15 | access to local variable x : C | +| Operator.cs:57:17:57:28 | call to method Source : C | Operator.cs:59:15:59:15 | access to local variable x : C | +| Operator.cs:59:15:59:15 | access to local variable x : C | Operator.cs:49:28:49:28 | x : C | | Operator.cs:59:15:59:15 | access to local variable x : C | Operator.cs:49:28:49:28 | x : C | | Operator.cs:62:33:62:33 | y : C | Operator.cs:64:21:64:21 | access to parameter y : C | +| Operator.cs:62:33:62:33 | y : C | Operator.cs:64:21:64:21 | access to parameter y : C | +| Operator.cs:64:17:64:21 | call to operator / : C | Operator.cs:65:14:65:14 | (...) ... | | Operator.cs:64:17:64:21 | call to operator / : C | Operator.cs:65:14:65:14 | (...) ... | | Operator.cs:64:21:64:21 | access to parameter y : C | Operator.cs:21:43:21:43 | y : C | +| Operator.cs:64:21:64:21 | access to parameter y : C | Operator.cs:21:43:21:43 | y : C | +| Operator.cs:64:21:64:21 | access to parameter y : C | Operator.cs:64:17:64:21 | call to operator / : C | | Operator.cs:64:21:64:21 | access to parameter y : C | Operator.cs:64:17:64:21 | call to operator / : C | | Operator.cs:71:17:71:29 | call to method Source : C | Operator.cs:72:18:72:18 | access to local variable y : C | +| Operator.cs:71:17:71:29 | call to method Source : C | Operator.cs:72:18:72:18 | access to local variable y : C | +| Operator.cs:72:18:72:18 | access to local variable y : C | Operator.cs:62:33:62:33 | y : C | | Operator.cs:72:18:72:18 | access to local variable y : C | Operator.cs:62:33:62:33 | y : C | | Operator.cs:75:33:75:33 | y : C | Operator.cs:77:29:77:29 | access to parameter y : C | +| Operator.cs:75:33:75:33 | y : C | Operator.cs:77:29:77:29 | access to parameter y : C | +| Operator.cs:77:25:77:29 | call to operator checked / : C | Operator.cs:78:14:78:14 | (...) ... | | Operator.cs:77:25:77:29 | call to operator checked / : C | Operator.cs:78:14:78:14 | (...) ... | | Operator.cs:77:29:77:29 | access to parameter y : C | Operator.cs:22:51:22:51 | y : C | +| Operator.cs:77:29:77:29 | access to parameter y : C | Operator.cs:22:51:22:51 | y : C | +| Operator.cs:77:29:77:29 | access to parameter y : C | Operator.cs:77:25:77:29 | call to operator checked / : C | | Operator.cs:77:29:77:29 | access to parameter y : C | Operator.cs:77:25:77:29 | call to operator checked / : C | | Operator.cs:84:17:84:29 | call to method Source : C | Operator.cs:85:18:85:18 | access to local variable y : C | +| Operator.cs:84:17:84:29 | call to method Source : C | Operator.cs:85:18:85:18 | access to local variable y : C | +| Operator.cs:85:18:85:18 | access to local variable y : C | Operator.cs:75:33:75:33 | y : C | | Operator.cs:85:18:85:18 | access to local variable y : C | Operator.cs:75:33:75:33 | y : C | nodes | Operator.cs:9:39:9:39 | x : C | semmle.label | x : C | +| Operator.cs:9:39:9:39 | x : C | semmle.label | x : C | +| Operator.cs:9:50:9:50 | access to parameter x : C | semmle.label | access to parameter x : C | | Operator.cs:9:50:9:50 | access to parameter x : C | semmle.label | access to parameter x : C | | Operator.cs:16:38:16:38 | x : C | semmle.label | x : C | +| Operator.cs:16:38:16:38 | x : C | semmle.label | x : C | +| Operator.cs:16:49:16:49 | access to parameter x : C | semmle.label | access to parameter x : C | | Operator.cs:16:49:16:49 | access to parameter x : C | semmle.label | access to parameter x : C | | Operator.cs:18:51:18:51 | y : C | semmle.label | y : C | +| Operator.cs:18:51:18:51 | y : C | semmle.label | y : C | +| Operator.cs:18:57:18:57 | access to parameter y : C | semmle.label | access to parameter y : C | | Operator.cs:18:57:18:57 | access to parameter y : C | semmle.label | access to parameter y : C | | Operator.cs:19:38:19:38 | x : C | semmle.label | x : C | +| Operator.cs:19:38:19:38 | x : C | semmle.label | x : C | +| Operator.cs:19:49:19:49 | access to parameter x : C | semmle.label | access to parameter x : C | | Operator.cs:19:49:19:49 | access to parameter x : C | semmle.label | access to parameter x : C | | Operator.cs:21:43:21:43 | y : C | semmle.label | y : C | +| Operator.cs:21:43:21:43 | y : C | semmle.label | y : C | +| Operator.cs:21:49:21:49 | access to parameter y : C | semmle.label | access to parameter y : C | | Operator.cs:21:49:21:49 | access to parameter y : C | semmle.label | access to parameter y : C | | Operator.cs:22:51:22:51 | y : C | semmle.label | y : C | +| Operator.cs:22:51:22:51 | y : C | semmle.label | y : C | +| Operator.cs:22:57:22:57 | access to parameter y : C | semmle.label | access to parameter y : C | | Operator.cs:22:57:22:57 | access to parameter y : C | semmle.label | access to parameter y : C | | Operator.cs:27:17:27:28 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:27:17:27:28 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:29:17:29:17 | access to local variable x : C | semmle.label | access to local variable x : C | | Operator.cs:29:17:29:17 | access to local variable x : C | semmle.label | access to local variable x : C | | Operator.cs:29:17:29:21 | call to operator + : C | semmle.label | call to operator + : C | +| Operator.cs:29:17:29:21 | call to operator + : C | semmle.label | call to operator + : C | +| Operator.cs:30:14:30:14 | access to local variable z | semmle.label | access to local variable z | | Operator.cs:30:14:30:14 | access to local variable z | semmle.label | access to local variable z | | Operator.cs:35:17:35:28 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:35:17:35:28 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:37:27:37:27 | access to local variable x : C | semmle.label | access to local variable x : C | | Operator.cs:37:27:37:27 | access to local variable x : C | semmle.label | access to local variable x : C | | Operator.cs:37:27:37:31 | call to operator - : C | semmle.label | call to operator - : C | +| Operator.cs:37:27:37:31 | call to operator - : C | semmle.label | call to operator - : C | +| Operator.cs:38:14:38:14 | access to local variable z | semmle.label | access to local variable z | | Operator.cs:38:14:38:14 | access to local variable z | semmle.label | access to local variable z | | Operator.cs:44:17:44:28 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:44:17:44:28 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:45:25:45:29 | call to operator checked - : C | semmle.label | call to operator checked - : C | | Operator.cs:45:25:45:29 | call to operator checked - : C | semmle.label | call to operator checked - : C | | Operator.cs:45:29:45:29 | access to local variable y : C | semmle.label | access to local variable y : C | +| Operator.cs:45:29:45:29 | access to local variable y : C | semmle.label | access to local variable y : C | +| Operator.cs:46:14:46:14 | access to local variable z | semmle.label | access to local variable z | | Operator.cs:46:14:46:14 | access to local variable z | semmle.label | access to local variable z | | Operator.cs:49:28:49:28 | x : C | semmle.label | x : C | +| Operator.cs:49:28:49:28 | x : C | semmle.label | x : C | +| Operator.cs:51:17:51:17 | access to parameter x : C | semmle.label | access to parameter x : C | | Operator.cs:51:17:51:17 | access to parameter x : C | semmle.label | access to parameter x : C | | Operator.cs:51:17:51:21 | call to operator * : C | semmle.label | call to operator * : C | +| Operator.cs:51:17:51:21 | call to operator * : C | semmle.label | call to operator * : C | +| Operator.cs:52:14:52:14 | (...) ... | semmle.label | (...) ... | | Operator.cs:52:14:52:14 | (...) ... | semmle.label | (...) ... | | Operator.cs:57:17:57:28 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:57:17:57:28 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:59:15:59:15 | access to local variable x : C | semmle.label | access to local variable x : C | | Operator.cs:59:15:59:15 | access to local variable x : C | semmle.label | access to local variable x : C | | Operator.cs:62:33:62:33 | y : C | semmle.label | y : C | +| Operator.cs:62:33:62:33 | y : C | semmle.label | y : C | +| Operator.cs:64:17:64:21 | call to operator / : C | semmle.label | call to operator / : C | | Operator.cs:64:17:64:21 | call to operator / : C | semmle.label | call to operator / : C | | Operator.cs:64:21:64:21 | access to parameter y : C | semmle.label | access to parameter y : C | +| Operator.cs:64:21:64:21 | access to parameter y : C | semmle.label | access to parameter y : C | +| Operator.cs:65:14:65:14 | (...) ... | semmle.label | (...) ... | | Operator.cs:65:14:65:14 | (...) ... | semmle.label | (...) ... | | Operator.cs:71:17:71:29 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:71:17:71:29 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:72:18:72:18 | access to local variable y : C | semmle.label | access to local variable y : C | | Operator.cs:72:18:72:18 | access to local variable y : C | semmle.label | access to local variable y : C | | Operator.cs:75:33:75:33 | y : C | semmle.label | y : C | +| Operator.cs:75:33:75:33 | y : C | semmle.label | y : C | +| Operator.cs:77:25:77:29 | call to operator checked / : C | semmle.label | call to operator checked / : C | | Operator.cs:77:25:77:29 | call to operator checked / : C | semmle.label | call to operator checked / : C | | Operator.cs:77:29:77:29 | access to parameter y : C | semmle.label | access to parameter y : C | +| Operator.cs:77:29:77:29 | access to parameter y : C | semmle.label | access to parameter y : C | +| Operator.cs:78:14:78:14 | (...) ... | semmle.label | (...) ... | | Operator.cs:78:14:78:14 | (...) ... | semmle.label | (...) ... | | Operator.cs:84:17:84:29 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:84:17:84:29 | call to method Source : C | semmle.label | call to method Source : C | +| Operator.cs:85:18:85:18 | access to local variable y : C | semmle.label | access to local variable y : C | | Operator.cs:85:18:85:18 | access to local variable y : C | semmle.label | access to local variable y : C | subpaths | Operator.cs:29:17:29:17 | access to local variable x : C | Operator.cs:16:38:16:38 | x : C | Operator.cs:16:49:16:49 | access to parameter x : C | Operator.cs:29:17:29:21 | call to operator + : C | +| Operator.cs:29:17:29:17 | access to local variable x : C | Operator.cs:16:38:16:38 | x : C | Operator.cs:16:49:16:49 | access to parameter x : C | Operator.cs:29:17:29:21 | call to operator + : C | +| Operator.cs:37:27:37:27 | access to local variable x : C | Operator.cs:19:38:19:38 | x : C | Operator.cs:19:49:19:49 | access to parameter x : C | Operator.cs:37:27:37:31 | call to operator - : C | | Operator.cs:37:27:37:27 | access to local variable x : C | Operator.cs:19:38:19:38 | x : C | Operator.cs:19:49:19:49 | access to parameter x : C | Operator.cs:37:27:37:31 | call to operator - : C | | Operator.cs:45:29:45:29 | access to local variable y : C | Operator.cs:18:51:18:51 | y : C | Operator.cs:18:57:18:57 | access to parameter y : C | Operator.cs:45:25:45:29 | call to operator checked - : C | +| Operator.cs:45:29:45:29 | access to local variable y : C | Operator.cs:18:51:18:51 | y : C | Operator.cs:18:57:18:57 | access to parameter y : C | Operator.cs:45:25:45:29 | call to operator checked - : C | +| Operator.cs:51:17:51:17 | access to parameter x : C | Operator.cs:9:39:9:39 | x : C | Operator.cs:9:50:9:50 | access to parameter x : C | Operator.cs:51:17:51:21 | call to operator * : C | | Operator.cs:51:17:51:17 | access to parameter x : C | Operator.cs:9:39:9:39 | x : C | Operator.cs:9:50:9:50 | access to parameter x : C | Operator.cs:51:17:51:21 | call to operator * : C | | Operator.cs:64:21:64:21 | access to parameter y : C | Operator.cs:21:43:21:43 | y : C | Operator.cs:21:49:21:49 | access to parameter y : C | Operator.cs:64:17:64:21 | call to operator / : C | +| Operator.cs:64:21:64:21 | access to parameter y : C | Operator.cs:21:43:21:43 | y : C | Operator.cs:21:49:21:49 | access to parameter y : C | Operator.cs:64:17:64:21 | call to operator / : C | +| Operator.cs:77:29:77:29 | access to parameter y : C | Operator.cs:22:51:22:51 | y : C | Operator.cs:22:57:22:57 | access to parameter y : C | Operator.cs:77:25:77:29 | call to operator checked / : C | | Operator.cs:77:29:77:29 | access to parameter y : C | Operator.cs:22:51:22:51 | y : C | Operator.cs:22:57:22:57 | access to parameter y : C | Operator.cs:77:25:77:29 | call to operator checked / : C | #select | Operator.cs:30:14:30:14 | access to local variable z | Operator.cs:27:17:27:28 | call to method Source : C | Operator.cs:30:14:30:14 | access to local variable z | $@ | Operator.cs:27:17:27:28 | call to method Source : C | call to method Source : C | +| Operator.cs:30:14:30:14 | access to local variable z | Operator.cs:27:17:27:28 | call to method Source : C | Operator.cs:30:14:30:14 | access to local variable z | $@ | Operator.cs:27:17:27:28 | call to method Source : C | call to method Source : C | +| Operator.cs:38:14:38:14 | access to local variable z | Operator.cs:35:17:35:28 | call to method Source : C | Operator.cs:38:14:38:14 | access to local variable z | $@ | Operator.cs:35:17:35:28 | call to method Source : C | call to method Source : C | | Operator.cs:38:14:38:14 | access to local variable z | Operator.cs:35:17:35:28 | call to method Source : C | Operator.cs:38:14:38:14 | access to local variable z | $@ | Operator.cs:35:17:35:28 | call to method Source : C | call to method Source : C | | Operator.cs:46:14:46:14 | access to local variable z | Operator.cs:44:17:44:28 | call to method Source : C | Operator.cs:46:14:46:14 | access to local variable z | $@ | Operator.cs:44:17:44:28 | call to method Source : C | call to method Source : C | +| Operator.cs:46:14:46:14 | access to local variable z | Operator.cs:44:17:44:28 | call to method Source : C | Operator.cs:46:14:46:14 | access to local variable z | $@ | Operator.cs:44:17:44:28 | call to method Source : C | call to method Source : C | +| Operator.cs:52:14:52:14 | (...) ... | Operator.cs:57:17:57:28 | call to method Source : C | Operator.cs:52:14:52:14 | (...) ... | $@ | Operator.cs:57:17:57:28 | call to method Source : C | call to method Source : C | | Operator.cs:52:14:52:14 | (...) ... | Operator.cs:57:17:57:28 | call to method Source : C | Operator.cs:52:14:52:14 | (...) ... | $@ | Operator.cs:57:17:57:28 | call to method Source : C | call to method Source : C | | Operator.cs:65:14:65:14 | (...) ... | Operator.cs:71:17:71:29 | call to method Source : C | Operator.cs:65:14:65:14 | (...) ... | $@ | Operator.cs:71:17:71:29 | call to method Source : C | call to method Source : C | +| Operator.cs:65:14:65:14 | (...) ... | Operator.cs:71:17:71:29 | call to method Source : C | Operator.cs:65:14:65:14 | (...) ... | $@ | Operator.cs:71:17:71:29 | call to method Source : C | call to method Source : C | +| Operator.cs:78:14:78:14 | (...) ... | Operator.cs:84:17:84:29 | call to method Source : C | Operator.cs:78:14:78:14 | (...) ... | $@ | Operator.cs:84:17:84:29 | call to method Source : C | call to method Source : C | | Operator.cs:78:14:78:14 | (...) ... | Operator.cs:84:17:84:29 | call to method Source : C | Operator.cs:78:14:78:14 | (...) ... | $@ | Operator.cs:84:17:84:29 | call to method Source : C | call to method Source : C | diff --git a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.ql b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.ql index 39395ad831b..9336e1b28be 100644 --- a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.ql @@ -5,8 +5,8 @@ import csharp import TestUtilities.InlineFlowTest import DefaultFlowTest -import ValueFlow::PathGraph +import PathGraph -from ValueFlow::PathNode source, ValueFlow::PathNode sink -where ValueFlow::flowPath(source, sink) +from PathNode source, PathNode sink +where flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.ql b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.ql index 39395ad831b..9336e1b28be 100644 --- a/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.ql @@ -5,8 +5,8 @@ import csharp import TestUtilities.InlineFlowTest import DefaultFlowTest -import ValueFlow::PathGraph +import PathGraph -from ValueFlow::PathNode source, ValueFlow::PathNode sink -where ValueFlow::flowPath(source, sink) +from PathNode source, PathNode sink +where flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected index bb1715df029..10b9a4b66ac 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected +++ b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected @@ -2,233 +2,461 @@ failures testFailures edges | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:10:21:10:22 | access to local variable o1 : Object | +| Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:10:21:10:22 | access to local variable o1 : Object | +| Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:10:29:10:30 | access to local variable o2 : Object | | Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:10:29:10:30 | access to local variable o2 : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item1] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item1] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item1] : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item1] : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item1] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item1] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:26:14:26:14 | access to local variable x : ValueTuple> [field Item1] : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:26:14:26:14 | access to local variable x : ValueTuple> [field Item1] : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:27:14:27:14 | access to local variable x : ValueTuple> [field Item1] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:27:14:27:14 | access to local variable x : ValueTuple> [field Item1] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:29:14:29:14 | access to local variable x : ValueTuple> [field Item2, field Item2] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:29:14:29:14 | access to local variable x : ValueTuple> [field Item2, field Item2] : Object | +| Tuples.cs:10:21:10:22 | access to local variable o1 : Object | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | | Tuples.cs:10:21:10:22 | access to local variable o1 : Object | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | | Tuples.cs:10:25:10:31 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | +| Tuples.cs:10:25:10:31 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | +| Tuples.cs:10:29:10:30 | access to local variable o2 : Object | Tuples.cs:10:25:10:31 | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:10:29:10:30 | access to local variable o2 : Object | Tuples.cs:10:25:10:31 | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:11:9:11:27 | SSA def(c) : Object | +| Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:11:9:11:27 | SSA def(c) : Object | +| Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:11:9:11:27 | SSA def(a) : Object | | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:11:9:11:27 | SSA def(a) : Object | | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:11:9:11:27 | SSA def(a) : Object | Tuples.cs:12:14:12:14 | access to local variable a | | Tuples.cs:11:9:11:27 | SSA def(a) : Object | Tuples.cs:12:14:12:14 | access to local variable a | | Tuples.cs:11:9:11:27 | SSA def(c) : Object | Tuples.cs:14:14:14:14 | access to local variable c | +| Tuples.cs:11:9:11:27 | SSA def(c) : Object | Tuples.cs:14:14:14:14 | access to local variable c | +| Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:16:9:16:23 | SSA def(a) : Object | | Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:16:9:16:23 | SSA def(a) : Object | | Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:16:13:16:18 | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:16:13:16:18 | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:16:9:16:23 | SSA def(a) : Object | Tuples.cs:17:14:17:14 | access to local variable a | | Tuples.cs:16:9:16:23 | SSA def(a) : Object | Tuples.cs:17:14:17:14 | access to local variable a | | Tuples.cs:16:9:16:23 | SSA def(c) : Object | Tuples.cs:19:14:19:14 | access to local variable c | +| Tuples.cs:16:9:16:23 | SSA def(c) : Object | Tuples.cs:19:14:19:14 | access to local variable c | +| Tuples.cs:16:13:16:18 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:16:9:16:23 | SSA def(c) : Object | | Tuples.cs:16:13:16:18 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:16:9:16:23 | SSA def(c) : Object | | Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:21:9:21:26 | SSA def(p) : Object | +| Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:21:9:21:26 | SSA def(p) : Object | +| Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:21:9:21:26 | SSA def(q) : ValueTuple [field Item2] : Object | | Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:21:9:21:26 | SSA def(q) : ValueTuple [field Item2] : Object | | Tuples.cs:21:9:21:26 | SSA def(p) : Object | Tuples.cs:22:14:22:14 | access to local variable p | +| Tuples.cs:21:9:21:26 | SSA def(p) : Object | Tuples.cs:22:14:22:14 | access to local variable p | +| Tuples.cs:21:9:21:26 | SSA def(q) : ValueTuple [field Item2] : Object | Tuples.cs:24:14:24:14 | access to local variable q : ValueTuple [field Item2] : Object | | Tuples.cs:21:9:21:26 | SSA def(q) : ValueTuple [field Item2] : Object | Tuples.cs:24:14:24:14 | access to local variable q : ValueTuple [field Item2] : Object | | Tuples.cs:24:14:24:14 | access to local variable q : ValueTuple [field Item2] : Object | Tuples.cs:24:14:24:20 | access to field Item2 | +| Tuples.cs:24:14:24:14 | access to local variable q : ValueTuple [field Item2] : Object | Tuples.cs:24:14:24:20 | access to field Item2 | +| Tuples.cs:26:14:26:14 | access to local variable x : ValueTuple> [field Item1] : Object | Tuples.cs:26:14:26:20 | access to field Item1 | | Tuples.cs:26:14:26:14 | access to local variable x : ValueTuple> [field Item1] : Object | Tuples.cs:26:14:26:20 | access to field Item1 | | Tuples.cs:27:14:27:14 | access to local variable x : ValueTuple> [field Item1] : Object | Tuples.cs:27:14:27:16 | access to field Item1 | +| Tuples.cs:27:14:27:14 | access to local variable x : ValueTuple> [field Item1] : Object | Tuples.cs:27:14:27:16 | access to field Item1 | +| Tuples.cs:29:14:29:14 | access to local variable x : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:29:14:29:20 | access to field Item2 : ValueTuple [field Item2] : Object | | Tuples.cs:29:14:29:14 | access to local variable x : ValueTuple> [field Item2, field Item2] : Object | Tuples.cs:29:14:29:20 | access to field Item2 : ValueTuple [field Item2] : Object | | Tuples.cs:29:14:29:20 | access to field Item2 : ValueTuple [field Item2] : Object | Tuples.cs:29:14:29:26 | access to field Item2 | +| Tuples.cs:29:14:29:20 | access to field Item2 : ValueTuple [field Item2] : Object | Tuples.cs:29:14:29:26 | access to field Item2 | +| Tuples.cs:34:18:34:34 | call to method Source : Object | Tuples.cs:37:18:37:19 | access to local variable o1 : Object | | Tuples.cs:34:18:34:34 | call to method Source : Object | Tuples.cs:37:18:37:19 | access to local variable o1 : Object | | Tuples.cs:35:18:35:34 | call to method Source : Object | Tuples.cs:37:46:37:47 | access to local variable o2 : Object | +| Tuples.cs:35:18:35:34 | call to method Source : Object | Tuples.cs:37:46:37:47 | access to local variable o2 : Object | +| Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:38:14:38:14 | access to local variable x : ValueTuple> [field Item1] : Object | | Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item1] : Object | Tuples.cs:38:14:38:14 | access to local variable x : ValueTuple> [field Item1] : Object | | Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item10] : Object | Tuples.cs:40:14:40:14 | access to local variable x : ValueTuple> [field Item10] : Object | +| Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item10] : Object | Tuples.cs:40:14:40:14 | access to local variable x : ValueTuple> [field Item10] : Object | +| Tuples.cs:37:18:37:19 | access to local variable o1 : Object | Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item1] : Object | | Tuples.cs:37:18:37:19 | access to local variable o1 : Object | Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item1] : Object | | Tuples.cs:37:46:37:47 | access to local variable o2 : Object | Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item10] : Object | +| Tuples.cs:37:46:37:47 | access to local variable o2 : Object | Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item10] : Object | +| Tuples.cs:38:14:38:14 | access to local variable x : ValueTuple> [field Item1] : Object | Tuples.cs:38:14:38:20 | access to field Item1 | | Tuples.cs:38:14:38:14 | access to local variable x : ValueTuple> [field Item1] : Object | Tuples.cs:38:14:38:20 | access to field Item1 | | Tuples.cs:40:14:40:14 | access to local variable x : ValueTuple> [field Item10] : Object | Tuples.cs:40:14:40:21 | access to field Item10 | +| Tuples.cs:40:14:40:14 | access to local variable x : ValueTuple> [field Item10] : Object | Tuples.cs:40:14:40:21 | access to field Item10 | +| Tuples.cs:45:17:45:33 | call to method Source : String | Tuples.cs:46:48:46:48 | access to local variable o : String | | Tuples.cs:45:17:45:33 | call to method Source : String | Tuples.cs:46:48:46:48 | access to local variable o : String | | Tuples.cs:46:17:46:55 | (...) ... : ValueTuple [field Item1] : String | Tuples.cs:47:14:47:14 | access to local variable x : ValueTuple [field Item1] : String | +| Tuples.cs:46:17:46:55 | (...) ... : ValueTuple [field Item1] : String | Tuples.cs:47:14:47:14 | access to local variable x : ValueTuple [field Item1] : String | +| Tuples.cs:46:47:46:55 | (..., ...) : ValueTuple [field Item1] : String | Tuples.cs:46:17:46:55 | (...) ... : ValueTuple [field Item1] : String | | Tuples.cs:46:47:46:55 | (..., ...) : ValueTuple [field Item1] : String | Tuples.cs:46:17:46:55 | (...) ... : ValueTuple [field Item1] : String | | Tuples.cs:46:48:46:48 | access to local variable o : String | Tuples.cs:46:47:46:55 | (..., ...) : ValueTuple [field Item1] : String | +| Tuples.cs:46:48:46:48 | access to local variable o : String | Tuples.cs:46:47:46:55 | (..., ...) : ValueTuple [field Item1] : String | +| Tuples.cs:47:14:47:14 | access to local variable x : ValueTuple [field Item1] : String | Tuples.cs:47:14:47:20 | access to field Item1 | | Tuples.cs:47:14:47:14 | access to local variable x : ValueTuple [field Item1] : String | Tuples.cs:47:14:47:20 | access to field Item1 | | Tuples.cs:57:18:57:34 | call to method Source : String | Tuples.cs:59:18:59:19 | access to local variable o1 : String | +| Tuples.cs:57:18:57:34 | call to method Source : String | Tuples.cs:59:18:59:19 | access to local variable o1 : String | +| Tuples.cs:58:18:58:34 | call to method Source : String | Tuples.cs:59:26:59:27 | access to local variable o2 : String | | Tuples.cs:58:18:58:34 | call to method Source : String | Tuples.cs:59:26:59:27 | access to local variable o2 : String | | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item2, field Item2] : String | | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item2, field Item2] : String | | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | | Tuples.cs:59:18:59:19 | access to local variable o1 : String | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:59:18:59:19 | access to local variable o1 : String | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:59:22:59:28 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | | Tuples.cs:59:22:59:28 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | | Tuples.cs:59:26:59:27 | access to local variable o2 : String | Tuples.cs:59:22:59:28 | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:59:26:59:27 | access to local variable o2 : String | Tuples.cs:59:22:59:28 | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:63:22:63:22 | access to local variable t : ValueTuple,Int32> [field Item1] : String | | Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:63:22:63:22 | access to local variable t : ValueTuple,Int32> [field Item1] : String | | Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:64:22:64:22 | access to local variable t : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:64:22:64:22 | access to local variable t : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:63:22:63:22 | access to local variable t : ValueTuple,Int32> [field Item1] : String | Tuples.cs:63:22:63:28 | access to field Item1 | | Tuples.cs:63:22:63:22 | access to local variable t : ValueTuple,Int32> [field Item1] : String | Tuples.cs:63:22:63:28 | access to field Item1 | | Tuples.cs:64:22:64:22 | access to local variable t : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:64:22:64:28 | access to field Item2 : ValueTuple [field Item2] : String | +| Tuples.cs:64:22:64:22 | access to local variable t : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:64:22:64:28 | access to field Item2 : ValueTuple [field Item2] : String | +| Tuples.cs:64:22:64:28 | access to field Item2 : ValueTuple [field Item2] : String | Tuples.cs:64:22:64:34 | access to field Item2 | | Tuples.cs:64:22:64:28 | access to field Item2 : ValueTuple [field Item2] : String | Tuples.cs:64:22:64:34 | access to field Item2 | | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:67:30:67:30 | SSA def(c) : String | +| Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:67:30:67:30 | SSA def(c) : String | +| Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:67:23:67:23 | SSA def(a) : String | | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:67:23:67:23 | SSA def(a) : String | | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:67:23:67:23 | SSA def(a) : String | Tuples.cs:68:22:68:22 | access to local variable a | | Tuples.cs:67:23:67:23 | SSA def(a) : String | Tuples.cs:68:22:68:22 | access to local variable a | | Tuples.cs:67:30:67:30 | SSA def(c) : String | Tuples.cs:69:22:69:22 | access to local variable c | +| Tuples.cs:67:30:67:30 | SSA def(c) : String | Tuples.cs:69:22:69:22 | access to local variable c | +| Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:87:30:87:30 | SSA def(r) : String | | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple [field Item2] : String | Tuples.cs:87:30:87:30 | SSA def(r) : String | | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:87:23:87:23 | SSA def(p) : String | +| Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | Tuples.cs:87:23:87:23 | SSA def(p) : String | +| Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple [field Item2] : String | | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple [field Item2] : String | | Tuples.cs:87:23:87:23 | SSA def(p) : String | Tuples.cs:89:18:89:18 | access to local variable p | +| Tuples.cs:87:23:87:23 | SSA def(p) : String | Tuples.cs:89:18:89:18 | access to local variable p | +| Tuples.cs:87:30:87:30 | SSA def(r) : String | Tuples.cs:90:18:90:18 | access to local variable r | | Tuples.cs:87:30:87:30 | SSA def(r) : String | Tuples.cs:90:18:90:18 | access to local variable r | | Tuples.cs:99:17:99:33 | call to method Source : String | Tuples.cs:100:24:100:24 | access to local variable o : String | +| Tuples.cs:99:17:99:33 | call to method Source : String | Tuples.cs:100:24:100:24 | access to local variable o : String | +| Tuples.cs:100:17:100:28 | object creation of type R1 : R1 [property i] : String | Tuples.cs:101:14:101:14 | access to local variable r : R1 [property i] : String | | Tuples.cs:100:17:100:28 | object creation of type R1 : R1 [property i] : String | Tuples.cs:101:14:101:14 | access to local variable r : R1 [property i] : String | | Tuples.cs:100:24:100:24 | access to local variable o : String | Tuples.cs:100:17:100:28 | object creation of type R1 : R1 [property i] : String | +| Tuples.cs:100:24:100:24 | access to local variable o : String | Tuples.cs:100:17:100:28 | object creation of type R1 : R1 [property i] : String | +| Tuples.cs:101:14:101:14 | access to local variable r : R1 [property i] : String | Tuples.cs:101:14:101:16 | access to property i | | Tuples.cs:101:14:101:14 | access to local variable r : R1 [property i] : String | Tuples.cs:101:14:101:16 | access to property i | | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:121:28:121:28 | access to local variable o : Object | +| Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:121:28:121:28 | access to local variable o : Object | +| Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:122:14:122:15 | access to local variable x1 | | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:122:14:122:15 | access to local variable x1 | | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:125:25:125:25 | access to local variable o : Object | +| Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:125:25:125:25 | access to local variable o : Object | +| Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:126:14:126:15 | access to local variable x2 | | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:126:14:126:15 | access to local variable x2 | | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:129:31:129:31 | access to local variable o : Object | +| Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:129:31:129:31 | access to local variable o : Object | +| Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:130:14:130:15 | access to local variable y3 | | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:130:14:130:15 | access to local variable y3 | | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:133:28:133:28 | access to local variable o : Object | +| Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:133:28:133:28 | access to local variable o : Object | +| Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:134:14:134:15 | access to local variable y4 | | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:134:14:134:15 | access to local variable y4 | | Tuples.cs:121:9:121:23 | (..., ...) : ValueTuple [field Item1] : Object | Tuples.cs:121:9:121:32 | SSA def(x1) : Object | +| Tuples.cs:121:9:121:23 | (..., ...) : ValueTuple [field Item1] : Object | Tuples.cs:121:9:121:32 | SSA def(x1) : Object | +| Tuples.cs:121:9:121:32 | SSA def(x1) : Object | Tuples.cs:122:14:122:15 | access to local variable x1 | | Tuples.cs:121:9:121:32 | SSA def(x1) : Object | Tuples.cs:122:14:122:15 | access to local variable x1 | | Tuples.cs:121:27:121:32 | (..., ...) : ValueTuple [field Item1] : Object | Tuples.cs:121:9:121:23 | (..., ...) : ValueTuple [field Item1] : Object | +| Tuples.cs:121:27:121:32 | (..., ...) : ValueTuple [field Item1] : Object | Tuples.cs:121:9:121:23 | (..., ...) : ValueTuple [field Item1] : Object | +| Tuples.cs:121:28:121:28 | access to local variable o : Object | Tuples.cs:121:27:121:32 | (..., ...) : ValueTuple [field Item1] : Object | | Tuples.cs:121:28:121:28 | access to local variable o : Object | Tuples.cs:121:27:121:32 | (..., ...) : ValueTuple [field Item1] : Object | | Tuples.cs:125:9:125:20 | (..., ...) : ValueTuple [field Item1] : Object | Tuples.cs:125:9:125:29 | SSA def(x2) : Object | +| Tuples.cs:125:9:125:20 | (..., ...) : ValueTuple [field Item1] : Object | Tuples.cs:125:9:125:29 | SSA def(x2) : Object | +| Tuples.cs:125:9:125:29 | SSA def(x2) : Object | Tuples.cs:126:14:126:15 | access to local variable x2 | | Tuples.cs:125:9:125:29 | SSA def(x2) : Object | Tuples.cs:126:14:126:15 | access to local variable x2 | | Tuples.cs:125:24:125:29 | (..., ...) : ValueTuple [field Item1] : Object | Tuples.cs:125:9:125:20 | (..., ...) : ValueTuple [field Item1] : Object | +| Tuples.cs:125:24:125:29 | (..., ...) : ValueTuple [field Item1] : Object | Tuples.cs:125:9:125:20 | (..., ...) : ValueTuple [field Item1] : Object | +| Tuples.cs:125:25:125:25 | access to local variable o : Object | Tuples.cs:125:24:125:29 | (..., ...) : ValueTuple [field Item1] : Object | | Tuples.cs:125:25:125:25 | access to local variable o : Object | Tuples.cs:125:24:125:29 | (..., ...) : ValueTuple [field Item1] : Object | | Tuples.cs:129:9:129:23 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:129:9:129:32 | SSA def(y3) : Object | +| Tuples.cs:129:9:129:23 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:129:9:129:32 | SSA def(y3) : Object | +| Tuples.cs:129:9:129:32 | SSA def(y3) : Object | Tuples.cs:130:14:130:15 | access to local variable y3 | | Tuples.cs:129:9:129:32 | SSA def(y3) : Object | Tuples.cs:130:14:130:15 | access to local variable y3 | | Tuples.cs:129:27:129:32 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:129:9:129:23 | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:129:27:129:32 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:129:9:129:23 | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:129:31:129:31 | access to local variable o : Object | Tuples.cs:129:27:129:32 | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:129:31:129:31 | access to local variable o : Object | Tuples.cs:129:27:129:32 | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:133:9:133:20 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:133:9:133:29 | SSA def(y4) : Object | +| Tuples.cs:133:9:133:20 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:133:9:133:29 | SSA def(y4) : Object | +| Tuples.cs:133:9:133:29 | SSA def(y4) : Object | Tuples.cs:134:14:134:15 | access to local variable y4 | | Tuples.cs:133:9:133:29 | SSA def(y4) : Object | Tuples.cs:134:14:134:15 | access to local variable y4 | | Tuples.cs:133:24:133:29 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:133:9:133:20 | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:133:24:133:29 | (..., ...) : ValueTuple [field Item2] : Object | Tuples.cs:133:9:133:20 | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:133:28:133:28 | access to local variable o : Object | Tuples.cs:133:24:133:29 | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:133:28:133:28 | access to local variable o : Object | Tuples.cs:133:24:133:29 | (..., ...) : ValueTuple [field Item2] : Object | nodes | Tuples.cs:7:18:7:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| Tuples.cs:7:18:7:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| Tuples.cs:8:18:8:34 | call to method Source : Object | semmle.label | call to method Source : Object | | Tuples.cs:8:18:8:34 | call to method Source : Object | semmle.label | call to method Source : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | semmle.label | (..., ...) : ValueTuple> [field Item1] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item1] : Object | semmle.label | (..., ...) : ValueTuple> [field Item1] : Object | +| Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | semmle.label | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | | Tuples.cs:10:17:10:32 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | semmle.label | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | | Tuples.cs:10:21:10:22 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| Tuples.cs:10:21:10:22 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| Tuples.cs:10:25:10:31 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:10:25:10:31 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:10:29:10:30 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| Tuples.cs:10:29:10:30 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item1] : Object | semmle.label | (..., ...) : ValueTuple> [field Item1] : Object | +| Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item1] : Object | semmle.label | (..., ...) : ValueTuple> [field Item1] : Object | +| Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | semmle.label | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | | Tuples.cs:11:9:11:23 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | semmle.label | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | | Tuples.cs:11:9:11:27 | SSA def(a) : Object | semmle.label | SSA def(a) : Object | +| Tuples.cs:11:9:11:27 | SSA def(a) : Object | semmle.label | SSA def(a) : Object | +| Tuples.cs:11:9:11:27 | SSA def(c) : Object | semmle.label | SSA def(c) : Object | | Tuples.cs:11:9:11:27 | SSA def(c) : Object | semmle.label | SSA def(c) : Object | | Tuples.cs:12:14:12:14 | access to local variable a | semmle.label | access to local variable a | +| Tuples.cs:12:14:12:14 | access to local variable a | semmle.label | access to local variable a | +| Tuples.cs:14:14:14:14 | access to local variable c | semmle.label | access to local variable c | | Tuples.cs:14:14:14:14 | access to local variable c | semmle.label | access to local variable c | | Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item1] : Object | semmle.label | (..., ...) : ValueTuple> [field Item1] : Object | +| Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item1] : Object | semmle.label | (..., ...) : ValueTuple> [field Item1] : Object | +| Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | semmle.label | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | | Tuples.cs:16:9:16:19 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | semmle.label | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | | Tuples.cs:16:9:16:23 | SSA def(a) : Object | semmle.label | SSA def(a) : Object | +| Tuples.cs:16:9:16:23 | SSA def(a) : Object | semmle.label | SSA def(a) : Object | +| Tuples.cs:16:9:16:23 | SSA def(c) : Object | semmle.label | SSA def(c) : Object | | Tuples.cs:16:9:16:23 | SSA def(c) : Object | semmle.label | SSA def(c) : Object | | Tuples.cs:16:13:16:18 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:16:13:16:18 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:17:14:17:14 | access to local variable a | semmle.label | access to local variable a | | Tuples.cs:17:14:17:14 | access to local variable a | semmle.label | access to local variable a | | Tuples.cs:19:14:19:14 | access to local variable c | semmle.label | access to local variable c | +| Tuples.cs:19:14:19:14 | access to local variable c | semmle.label | access to local variable c | +| Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item1] : Object | semmle.label | (..., ...) : ValueTuple> [field Item1] : Object | | Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item1] : Object | semmle.label | (..., ...) : ValueTuple> [field Item1] : Object | | Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | semmle.label | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | +| Tuples.cs:21:9:21:22 | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | semmle.label | (..., ...) : ValueTuple> [field Item2, field Item2] : Object | +| Tuples.cs:21:9:21:26 | SSA def(p) : Object | semmle.label | SSA def(p) : Object | | Tuples.cs:21:9:21:26 | SSA def(p) : Object | semmle.label | SSA def(p) : Object | | Tuples.cs:21:9:21:26 | SSA def(q) : ValueTuple [field Item2] : Object | semmle.label | SSA def(q) : ValueTuple [field Item2] : Object | +| Tuples.cs:21:9:21:26 | SSA def(q) : ValueTuple [field Item2] : Object | semmle.label | SSA def(q) : ValueTuple [field Item2] : Object | +| Tuples.cs:22:14:22:14 | access to local variable p | semmle.label | access to local variable p | | Tuples.cs:22:14:22:14 | access to local variable p | semmle.label | access to local variable p | | Tuples.cs:24:14:24:14 | access to local variable q : ValueTuple [field Item2] : Object | semmle.label | access to local variable q : ValueTuple [field Item2] : Object | +| Tuples.cs:24:14:24:14 | access to local variable q : ValueTuple [field Item2] : Object | semmle.label | access to local variable q : ValueTuple [field Item2] : Object | +| Tuples.cs:24:14:24:20 | access to field Item2 | semmle.label | access to field Item2 | | Tuples.cs:24:14:24:20 | access to field Item2 | semmle.label | access to field Item2 | | Tuples.cs:26:14:26:14 | access to local variable x : ValueTuple> [field Item1] : Object | semmle.label | access to local variable x : ValueTuple> [field Item1] : Object | +| Tuples.cs:26:14:26:14 | access to local variable x : ValueTuple> [field Item1] : Object | semmle.label | access to local variable x : ValueTuple> [field Item1] : Object | +| Tuples.cs:26:14:26:20 | access to field Item1 | semmle.label | access to field Item1 | | Tuples.cs:26:14:26:20 | access to field Item1 | semmle.label | access to field Item1 | | Tuples.cs:27:14:27:14 | access to local variable x : ValueTuple> [field Item1] : Object | semmle.label | access to local variable x : ValueTuple> [field Item1] : Object | +| Tuples.cs:27:14:27:14 | access to local variable x : ValueTuple> [field Item1] : Object | semmle.label | access to local variable x : ValueTuple> [field Item1] : Object | +| Tuples.cs:27:14:27:16 | access to field Item1 | semmle.label | access to field Item1 | | Tuples.cs:27:14:27:16 | access to field Item1 | semmle.label | access to field Item1 | | Tuples.cs:29:14:29:14 | access to local variable x : ValueTuple> [field Item2, field Item2] : Object | semmle.label | access to local variable x : ValueTuple> [field Item2, field Item2] : Object | +| Tuples.cs:29:14:29:14 | access to local variable x : ValueTuple> [field Item2, field Item2] : Object | semmle.label | access to local variable x : ValueTuple> [field Item2, field Item2] : Object | +| Tuples.cs:29:14:29:20 | access to field Item2 : ValueTuple [field Item2] : Object | semmle.label | access to field Item2 : ValueTuple [field Item2] : Object | | Tuples.cs:29:14:29:20 | access to field Item2 : ValueTuple [field Item2] : Object | semmle.label | access to field Item2 : ValueTuple [field Item2] : Object | | Tuples.cs:29:14:29:26 | access to field Item2 | semmle.label | access to field Item2 | +| Tuples.cs:29:14:29:26 | access to field Item2 | semmle.label | access to field Item2 | +| Tuples.cs:34:18:34:34 | call to method Source : Object | semmle.label | call to method Source : Object | | Tuples.cs:34:18:34:34 | call to method Source : Object | semmle.label | call to method Source : Object | | Tuples.cs:35:18:35:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| Tuples.cs:35:18:35:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item1] : Object | semmle.label | (..., ...) : ValueTuple> [field Item1] : Object | | Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item1] : Object | semmle.label | (..., ...) : ValueTuple> [field Item1] : Object | | Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item10] : Object | semmle.label | (..., ...) : ValueTuple> [field Item10] : Object | +| Tuples.cs:37:17:37:48 | (..., ...) : ValueTuple> [field Item10] : Object | semmle.label | (..., ...) : ValueTuple> [field Item10] : Object | +| Tuples.cs:37:18:37:19 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | | Tuples.cs:37:18:37:19 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | | Tuples.cs:37:46:37:47 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| Tuples.cs:37:46:37:47 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| Tuples.cs:38:14:38:14 | access to local variable x : ValueTuple> [field Item1] : Object | semmle.label | access to local variable x : ValueTuple> [field Item1] : Object | | Tuples.cs:38:14:38:14 | access to local variable x : ValueTuple> [field Item1] : Object | semmle.label | access to local variable x : ValueTuple> [field Item1] : Object | | Tuples.cs:38:14:38:20 | access to field Item1 | semmle.label | access to field Item1 | +| Tuples.cs:38:14:38:20 | access to field Item1 | semmle.label | access to field Item1 | +| Tuples.cs:40:14:40:14 | access to local variable x : ValueTuple> [field Item10] : Object | semmle.label | access to local variable x : ValueTuple> [field Item10] : Object | | Tuples.cs:40:14:40:14 | access to local variable x : ValueTuple> [field Item10] : Object | semmle.label | access to local variable x : ValueTuple> [field Item10] : Object | | Tuples.cs:40:14:40:21 | access to field Item10 | semmle.label | access to field Item10 | +| Tuples.cs:40:14:40:21 | access to field Item10 | semmle.label | access to field Item10 | +| Tuples.cs:45:17:45:33 | call to method Source : String | semmle.label | call to method Source : String | | Tuples.cs:45:17:45:33 | call to method Source : String | semmle.label | call to method Source : String | | Tuples.cs:46:17:46:55 | (...) ... : ValueTuple [field Item1] : String | semmle.label | (...) ... : ValueTuple [field Item1] : String | +| Tuples.cs:46:17:46:55 | (...) ... : ValueTuple [field Item1] : String | semmle.label | (...) ... : ValueTuple [field Item1] : String | +| Tuples.cs:46:47:46:55 | (..., ...) : ValueTuple [field Item1] : String | semmle.label | (..., ...) : ValueTuple [field Item1] : String | | Tuples.cs:46:47:46:55 | (..., ...) : ValueTuple [field Item1] : String | semmle.label | (..., ...) : ValueTuple [field Item1] : String | | Tuples.cs:46:48:46:48 | access to local variable o : String | semmle.label | access to local variable o : String | +| Tuples.cs:46:48:46:48 | access to local variable o : String | semmle.label | access to local variable o : String | +| Tuples.cs:47:14:47:14 | access to local variable x : ValueTuple [field Item1] : String | semmle.label | access to local variable x : ValueTuple [field Item1] : String | | Tuples.cs:47:14:47:14 | access to local variable x : ValueTuple [field Item1] : String | semmle.label | access to local variable x : ValueTuple [field Item1] : String | | Tuples.cs:47:14:47:20 | access to field Item1 | semmle.label | access to field Item1 | +| Tuples.cs:47:14:47:20 | access to field Item1 | semmle.label | access to field Item1 | +| Tuples.cs:57:18:57:34 | call to method Source : String | semmle.label | call to method Source : String | | Tuples.cs:57:18:57:34 | call to method Source : String | semmle.label | call to method Source : String | | Tuples.cs:58:18:58:34 | call to method Source : String | semmle.label | call to method Source : String | +| Tuples.cs:58:18:58:34 | call to method Source : String | semmle.label | call to method Source : String | +| Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item1] : String | | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item1] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item1] : String | | Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:59:17:59:32 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:59:18:59:19 | access to local variable o1 : String | semmle.label | access to local variable o1 : String | | Tuples.cs:59:18:59:19 | access to local variable o1 : String | semmle.label | access to local variable o1 : String | | Tuples.cs:59:22:59:28 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:59:22:59:28 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:59:26:59:27 | access to local variable o2 : String | semmle.label | access to local variable o2 : String | | Tuples.cs:59:26:59:27 | access to local variable o2 : String | semmle.label | access to local variable o2 : String | | Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item1] : String | semmle.label | SSA def(t) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item1] : String | semmle.label | SSA def(t) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | SSA def(t) : ValueTuple,Int32> [field Item2, field Item2] : String | | Tuples.cs:62:18:62:57 | SSA def(t) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | SSA def(t) : ValueTuple,Int32> [field Item2, field Item2] : String | | Tuples.cs:63:22:63:22 | access to local variable t : ValueTuple,Int32> [field Item1] : String | semmle.label | access to local variable t : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:63:22:63:22 | access to local variable t : ValueTuple,Int32> [field Item1] : String | semmle.label | access to local variable t : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:63:22:63:28 | access to field Item1 | semmle.label | access to field Item1 | | Tuples.cs:63:22:63:28 | access to field Item1 | semmle.label | access to field Item1 | | Tuples.cs:64:22:64:22 | access to local variable t : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | access to local variable t : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:64:22:64:22 | access to local variable t : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | access to local variable t : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:64:22:64:28 | access to field Item2 : ValueTuple [field Item2] : String | semmle.label | access to field Item2 : ValueTuple [field Item2] : String | | Tuples.cs:64:22:64:28 | access to field Item2 : ValueTuple [field Item2] : String | semmle.label | access to field Item2 : ValueTuple [field Item2] : String | | Tuples.cs:64:22:64:34 | access to field Item2 | semmle.label | access to field Item2 | +| Tuples.cs:64:22:64:34 | access to field Item2 | semmle.label | access to field Item2 | +| Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item1] : String | +| Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | | Tuples.cs:67:18:67:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | | Tuples.cs:67:23:67:23 | SSA def(a) : String | semmle.label | SSA def(a) : String | +| Tuples.cs:67:23:67:23 | SSA def(a) : String | semmle.label | SSA def(a) : String | +| Tuples.cs:67:30:67:30 | SSA def(c) : String | semmle.label | SSA def(c) : String | | Tuples.cs:67:30:67:30 | SSA def(c) : String | semmle.label | SSA def(c) : String | | Tuples.cs:68:22:68:22 | access to local variable a | semmle.label | access to local variable a | +| Tuples.cs:68:22:68:22 | access to local variable a | semmle.label | access to local variable a | +| Tuples.cs:69:22:69:22 | access to local variable c | semmle.label | access to local variable c | | Tuples.cs:69:22:69:22 | access to local variable c | semmle.label | access to local variable c | | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple [field Item2] : String | semmle.label | (..., ...) : ValueTuple [field Item2] : String | +| Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item1] : String | | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item1] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item1] : String | | Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:87:18:87:35 | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | semmle.label | (..., ...) : ValueTuple,Int32> [field Item2, field Item2] : String | +| Tuples.cs:87:23:87:23 | SSA def(p) : String | semmle.label | SSA def(p) : String | | Tuples.cs:87:23:87:23 | SSA def(p) : String | semmle.label | SSA def(p) : String | | Tuples.cs:87:30:87:30 | SSA def(r) : String | semmle.label | SSA def(r) : String | +| Tuples.cs:87:30:87:30 | SSA def(r) : String | semmle.label | SSA def(r) : String | +| Tuples.cs:89:18:89:18 | access to local variable p | semmle.label | access to local variable p | | Tuples.cs:89:18:89:18 | access to local variable p | semmle.label | access to local variable p | | Tuples.cs:90:18:90:18 | access to local variable r | semmle.label | access to local variable r | +| Tuples.cs:90:18:90:18 | access to local variable r | semmle.label | access to local variable r | +| Tuples.cs:99:17:99:33 | call to method Source : String | semmle.label | call to method Source : String | | Tuples.cs:99:17:99:33 | call to method Source : String | semmle.label | call to method Source : String | | Tuples.cs:100:17:100:28 | object creation of type R1 : R1 [property i] : String | semmle.label | object creation of type R1 : R1 [property i] : String | +| Tuples.cs:100:17:100:28 | object creation of type R1 : R1 [property i] : String | semmle.label | object creation of type R1 : R1 [property i] : String | +| Tuples.cs:100:24:100:24 | access to local variable o : String | semmle.label | access to local variable o : String | | Tuples.cs:100:24:100:24 | access to local variable o : String | semmle.label | access to local variable o : String | | Tuples.cs:101:14:101:14 | access to local variable r : R1 [property i] : String | semmle.label | access to local variable r : R1 [property i] : String | +| Tuples.cs:101:14:101:14 | access to local variable r : R1 [property i] : String | semmle.label | access to local variable r : R1 [property i] : String | +| Tuples.cs:101:14:101:16 | access to property i | semmle.label | access to property i | | Tuples.cs:101:14:101:16 | access to property i | semmle.label | access to property i | | Tuples.cs:118:17:118:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| Tuples.cs:118:17:118:33 | call to method Source : Object | semmle.label | call to method Source : Object | +| Tuples.cs:121:9:121:23 | (..., ...) : ValueTuple [field Item1] : Object | semmle.label | (..., ...) : ValueTuple [field Item1] : Object | | Tuples.cs:121:9:121:23 | (..., ...) : ValueTuple [field Item1] : Object | semmle.label | (..., ...) : ValueTuple [field Item1] : Object | | Tuples.cs:121:9:121:32 | SSA def(x1) : Object | semmle.label | SSA def(x1) : Object | +| Tuples.cs:121:9:121:32 | SSA def(x1) : Object | semmle.label | SSA def(x1) : Object | +| Tuples.cs:121:27:121:32 | (..., ...) : ValueTuple [field Item1] : Object | semmle.label | (..., ...) : ValueTuple [field Item1] : Object | | Tuples.cs:121:27:121:32 | (..., ...) : ValueTuple [field Item1] : Object | semmle.label | (..., ...) : ValueTuple [field Item1] : Object | | Tuples.cs:121:28:121:28 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Tuples.cs:121:28:121:28 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Tuples.cs:122:14:122:15 | access to local variable x1 | semmle.label | access to local variable x1 | | Tuples.cs:122:14:122:15 | access to local variable x1 | semmle.label | access to local variable x1 | | Tuples.cs:125:9:125:20 | (..., ...) : ValueTuple [field Item1] : Object | semmle.label | (..., ...) : ValueTuple [field Item1] : Object | +| Tuples.cs:125:9:125:20 | (..., ...) : ValueTuple [field Item1] : Object | semmle.label | (..., ...) : ValueTuple [field Item1] : Object | +| Tuples.cs:125:9:125:29 | SSA def(x2) : Object | semmle.label | SSA def(x2) : Object | | Tuples.cs:125:9:125:29 | SSA def(x2) : Object | semmle.label | SSA def(x2) : Object | | Tuples.cs:125:24:125:29 | (..., ...) : ValueTuple [field Item1] : Object | semmle.label | (..., ...) : ValueTuple [field Item1] : Object | +| Tuples.cs:125:24:125:29 | (..., ...) : ValueTuple [field Item1] : Object | semmle.label | (..., ...) : ValueTuple [field Item1] : Object | +| Tuples.cs:125:25:125:25 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Tuples.cs:125:25:125:25 | access to local variable o : Object | semmle.label | access to local variable o : Object | | Tuples.cs:126:14:126:15 | access to local variable x2 | semmle.label | access to local variable x2 | +| Tuples.cs:126:14:126:15 | access to local variable x2 | semmle.label | access to local variable x2 | +| Tuples.cs:129:9:129:23 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:129:9:129:23 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:129:9:129:32 | SSA def(y3) : Object | semmle.label | SSA def(y3) : Object | +| Tuples.cs:129:9:129:32 | SSA def(y3) : Object | semmle.label | SSA def(y3) : Object | +| Tuples.cs:129:27:129:32 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:129:27:129:32 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:129:31:129:31 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Tuples.cs:129:31:129:31 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Tuples.cs:130:14:130:15 | access to local variable y3 | semmle.label | access to local variable y3 | | Tuples.cs:130:14:130:15 | access to local variable y3 | semmle.label | access to local variable y3 | | Tuples.cs:133:9:133:20 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:133:9:133:20 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:133:9:133:29 | SSA def(y4) : Object | semmle.label | SSA def(y4) : Object | | Tuples.cs:133:9:133:29 | SSA def(y4) : Object | semmle.label | SSA def(y4) : Object | | Tuples.cs:133:24:133:29 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | +| Tuples.cs:133:24:133:29 | (..., ...) : ValueTuple [field Item2] : Object | semmle.label | (..., ...) : ValueTuple [field Item2] : Object | | Tuples.cs:133:28:133:28 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Tuples.cs:133:28:133:28 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| Tuples.cs:134:14:134:15 | access to local variable y4 | semmle.label | access to local variable y4 | | Tuples.cs:134:14:134:15 | access to local variable y4 | semmle.label | access to local variable y4 | subpaths #select | Tuples.cs:12:14:12:14 | access to local variable a | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:12:14:12:14 | access to local variable a | $@ | Tuples.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:12:14:12:14 | access to local variable a | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:12:14:12:14 | access to local variable a | $@ | Tuples.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:14:14:14:14 | access to local variable c | Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:14:14:14:14 | access to local variable c | $@ | Tuples.cs:8:18:8:34 | call to method Source : Object | call to method Source : Object | | Tuples.cs:14:14:14:14 | access to local variable c | Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:14:14:14:14 | access to local variable c | $@ | Tuples.cs:8:18:8:34 | call to method Source : Object | call to method Source : Object | | Tuples.cs:17:14:17:14 | access to local variable a | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:17:14:17:14 | access to local variable a | $@ | Tuples.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:17:14:17:14 | access to local variable a | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:17:14:17:14 | access to local variable a | $@ | Tuples.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:19:14:19:14 | access to local variable c | Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:19:14:19:14 | access to local variable c | $@ | Tuples.cs:8:18:8:34 | call to method Source : Object | call to method Source : Object | | Tuples.cs:19:14:19:14 | access to local variable c | Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:19:14:19:14 | access to local variable c | $@ | Tuples.cs:8:18:8:34 | call to method Source : Object | call to method Source : Object | | Tuples.cs:22:14:22:14 | access to local variable p | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:22:14:22:14 | access to local variable p | $@ | Tuples.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:22:14:22:14 | access to local variable p | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:22:14:22:14 | access to local variable p | $@ | Tuples.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:24:14:24:20 | access to field Item2 | Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:24:14:24:20 | access to field Item2 | $@ | Tuples.cs:8:18:8:34 | call to method Source : Object | call to method Source : Object | | Tuples.cs:24:14:24:20 | access to field Item2 | Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:24:14:24:20 | access to field Item2 | $@ | Tuples.cs:8:18:8:34 | call to method Source : Object | call to method Source : Object | | Tuples.cs:26:14:26:20 | access to field Item1 | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:26:14:26:20 | access to field Item1 | $@ | Tuples.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:26:14:26:20 | access to field Item1 | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:26:14:26:20 | access to field Item1 | $@ | Tuples.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:27:14:27:16 | access to field Item1 | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:27:14:27:16 | access to field Item1 | $@ | Tuples.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | | Tuples.cs:27:14:27:16 | access to field Item1 | Tuples.cs:7:18:7:34 | call to method Source : Object | Tuples.cs:27:14:27:16 | access to field Item1 | $@ | Tuples.cs:7:18:7:34 | call to method Source : Object | call to method Source : Object | | Tuples.cs:29:14:29:26 | access to field Item2 | Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:29:14:29:26 | access to field Item2 | $@ | Tuples.cs:8:18:8:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:29:14:29:26 | access to field Item2 | Tuples.cs:8:18:8:34 | call to method Source : Object | Tuples.cs:29:14:29:26 | access to field Item2 | $@ | Tuples.cs:8:18:8:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:38:14:38:20 | access to field Item1 | Tuples.cs:34:18:34:34 | call to method Source : Object | Tuples.cs:38:14:38:20 | access to field Item1 | $@ | Tuples.cs:34:18:34:34 | call to method Source : Object | call to method Source : Object | | Tuples.cs:38:14:38:20 | access to field Item1 | Tuples.cs:34:18:34:34 | call to method Source : Object | Tuples.cs:38:14:38:20 | access to field Item1 | $@ | Tuples.cs:34:18:34:34 | call to method Source : Object | call to method Source : Object | | Tuples.cs:40:14:40:21 | access to field Item10 | Tuples.cs:35:18:35:34 | call to method Source : Object | Tuples.cs:40:14:40:21 | access to field Item10 | $@ | Tuples.cs:35:18:35:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:40:14:40:21 | access to field Item10 | Tuples.cs:35:18:35:34 | call to method Source : Object | Tuples.cs:40:14:40:21 | access to field Item10 | $@ | Tuples.cs:35:18:35:34 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:47:14:47:20 | access to field Item1 | Tuples.cs:45:17:45:33 | call to method Source : String | Tuples.cs:47:14:47:20 | access to field Item1 | $@ | Tuples.cs:45:17:45:33 | call to method Source : String | call to method Source : String | | Tuples.cs:47:14:47:20 | access to field Item1 | Tuples.cs:45:17:45:33 | call to method Source : String | Tuples.cs:47:14:47:20 | access to field Item1 | $@ | Tuples.cs:45:17:45:33 | call to method Source : String | call to method Source : String | | Tuples.cs:63:22:63:28 | access to field Item1 | Tuples.cs:57:18:57:34 | call to method Source : String | Tuples.cs:63:22:63:28 | access to field Item1 | $@ | Tuples.cs:57:18:57:34 | call to method Source : String | call to method Source : String | +| Tuples.cs:63:22:63:28 | access to field Item1 | Tuples.cs:57:18:57:34 | call to method Source : String | Tuples.cs:63:22:63:28 | access to field Item1 | $@ | Tuples.cs:57:18:57:34 | call to method Source : String | call to method Source : String | +| Tuples.cs:64:22:64:34 | access to field Item2 | Tuples.cs:58:18:58:34 | call to method Source : String | Tuples.cs:64:22:64:34 | access to field Item2 | $@ | Tuples.cs:58:18:58:34 | call to method Source : String | call to method Source : String | | Tuples.cs:64:22:64:34 | access to field Item2 | Tuples.cs:58:18:58:34 | call to method Source : String | Tuples.cs:64:22:64:34 | access to field Item2 | $@ | Tuples.cs:58:18:58:34 | call to method Source : String | call to method Source : String | | Tuples.cs:68:22:68:22 | access to local variable a | Tuples.cs:57:18:57:34 | call to method Source : String | Tuples.cs:68:22:68:22 | access to local variable a | $@ | Tuples.cs:57:18:57:34 | call to method Source : String | call to method Source : String | +| Tuples.cs:68:22:68:22 | access to local variable a | Tuples.cs:57:18:57:34 | call to method Source : String | Tuples.cs:68:22:68:22 | access to local variable a | $@ | Tuples.cs:57:18:57:34 | call to method Source : String | call to method Source : String | +| Tuples.cs:69:22:69:22 | access to local variable c | Tuples.cs:58:18:58:34 | call to method Source : String | Tuples.cs:69:22:69:22 | access to local variable c | $@ | Tuples.cs:58:18:58:34 | call to method Source : String | call to method Source : String | | Tuples.cs:69:22:69:22 | access to local variable c | Tuples.cs:58:18:58:34 | call to method Source : String | Tuples.cs:69:22:69:22 | access to local variable c | $@ | Tuples.cs:58:18:58:34 | call to method Source : String | call to method Source : String | | Tuples.cs:89:18:89:18 | access to local variable p | Tuples.cs:57:18:57:34 | call to method Source : String | Tuples.cs:89:18:89:18 | access to local variable p | $@ | Tuples.cs:57:18:57:34 | call to method Source : String | call to method Source : String | +| Tuples.cs:89:18:89:18 | access to local variable p | Tuples.cs:57:18:57:34 | call to method Source : String | Tuples.cs:89:18:89:18 | access to local variable p | $@ | Tuples.cs:57:18:57:34 | call to method Source : String | call to method Source : String | +| Tuples.cs:90:18:90:18 | access to local variable r | Tuples.cs:58:18:58:34 | call to method Source : String | Tuples.cs:90:18:90:18 | access to local variable r | $@ | Tuples.cs:58:18:58:34 | call to method Source : String | call to method Source : String | | Tuples.cs:90:18:90:18 | access to local variable r | Tuples.cs:58:18:58:34 | call to method Source : String | Tuples.cs:90:18:90:18 | access to local variable r | $@ | Tuples.cs:58:18:58:34 | call to method Source : String | call to method Source : String | | Tuples.cs:101:14:101:16 | access to property i | Tuples.cs:99:17:99:33 | call to method Source : String | Tuples.cs:101:14:101:16 | access to property i | $@ | Tuples.cs:99:17:99:33 | call to method Source : String | call to method Source : String | +| Tuples.cs:101:14:101:16 | access to property i | Tuples.cs:99:17:99:33 | call to method Source : String | Tuples.cs:101:14:101:16 | access to property i | $@ | Tuples.cs:99:17:99:33 | call to method Source : String | call to method Source : String | +| Tuples.cs:122:14:122:15 | access to local variable x1 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:122:14:122:15 | access to local variable x1 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | | Tuples.cs:122:14:122:15 | access to local variable x1 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:122:14:122:15 | access to local variable x1 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | | Tuples.cs:126:14:126:15 | access to local variable x2 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:126:14:126:15 | access to local variable x2 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:126:14:126:15 | access to local variable x2 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:126:14:126:15 | access to local variable x2 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:130:14:130:15 | access to local variable y3 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:130:14:130:15 | access to local variable y3 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | | Tuples.cs:130:14:130:15 | access to local variable y3 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:130:14:130:15 | access to local variable y3 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | | Tuples.cs:134:14:134:15 | access to local variable y4 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:134:14:134:15 | access to local variable y4 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | +| Tuples.cs:134:14:134:15 | access to local variable y4 | Tuples.cs:118:17:118:33 | call to method Source : Object | Tuples.cs:134:14:134:15 | access to local variable y4 | $@ | Tuples.cs:118:17:118:33 | call to method Source : Object | call to method Source : Object | diff --git a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.ql b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.ql index 39395ad831b..9336e1b28be 100644 --- a/csharp/ql/test/library-tests/dataflow/tuples/Tuples.ql +++ b/csharp/ql/test/library-tests/dataflow/tuples/Tuples.ql @@ -5,8 +5,8 @@ import csharp import TestUtilities.InlineFlowTest import DefaultFlowTest -import ValueFlow::PathGraph +import PathGraph -from ValueFlow::PathNode source, ValueFlow::PathNode sink -where ValueFlow::flowPath(source, sink) +from PathNode source, PathNode sink +where flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() From bc42308bd3c824554beb349c92819dc124cd182f Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 19 Jun 2023 10:31:49 +0200 Subject: [PATCH 168/364] Java: fix formatting --- java/ql/test/TestUtilities/InlineFlowTest.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/java/ql/test/TestUtilities/InlineFlowTest.qll b/java/ql/test/TestUtilities/InlineFlowTest.qll index 45ba10ee149..34d7f75ee20 100644 --- a/java/ql/test/TestUtilities/InlineFlowTest.qll +++ b/java/ql/test/TestUtilities/InlineFlowTest.qll @@ -11,7 +11,6 @@ * from PathNode source, PathNode sink * where flowPath(source, sink) * select sink, source, sink, "$@", source, source.toString() - * ``` * * To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files. From 1f538cced3a19bdc6a6db5a1128c9897761de9fb Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Fri, 16 Jun 2023 13:33:41 +0100 Subject: [PATCH 169/364] Kotlin: Handle IrSyntheticBodyKind.ENUM_ENTRIES Generated by Kotlin 1.9 for some of our tests. --- .../src/main/kotlin/KotlinFileExtractor.kt | 11 ++++++----- .../utils/versions/v_1_4_32/SyntheticBodyKind.kt | 6 ++++++ .../utils/versions/v_1_8_0/SyntheticBodyKind.kt | 6 ++++++ java/ql/lib/config/semmlecode.dbscheme | 1 + 4 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/SyntheticBodyKind.kt create mode 100644 java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/SyntheticBodyKind.kt diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index c471662e631..b31452c888a 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -1701,12 +1701,13 @@ open class KotlinFileExtractor( private fun extractSyntheticBody(b: IrSyntheticBody, callable: Label) { with("synthetic body", b) { - when (b.kind) { - IrSyntheticBodyKind.ENUM_VALUES -> tw.writeKtSyntheticBody(callable, 1) - IrSyntheticBodyKind.ENUM_VALUEOF -> tw.writeKtSyntheticBody(callable, 2) + val kind = b.kind + when { + kind == IrSyntheticBodyKind.ENUM_VALUES -> tw.writeKtSyntheticBody(callable, 1) + kind == IrSyntheticBodyKind.ENUM_VALUEOF -> tw.writeKtSyntheticBody(callable, 2) + kind == kind_ENUM_ENTRIES -> tw.writeKtSyntheticBody(callable, 3) else -> { - // TODO: Support IrSyntheticBodyKind.ENUM_ENTRIES - logger.errorElement("Unhandled synthetic body kind " + b.kind.javaClass, b) + logger.errorElement("Unhandled synthetic body kind " + kind, b) } } } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/SyntheticBodyKind.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/SyntheticBodyKind.kt new file mode 100644 index 00000000000..fd3fc1f8e20 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/SyntheticBodyKind.kt @@ -0,0 +1,6 @@ +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind + +val kind_ENUM_ENTRIES: IrSyntheticBodyKind? = null + diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/SyntheticBodyKind.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/SyntheticBodyKind.kt new file mode 100644 index 00000000000..d0dbb5b1247 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/SyntheticBodyKind.kt @@ -0,0 +1,6 @@ +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind + +val kind_ENUM_ENTRIES: IrSyntheticBodyKind? = IrSyntheticBodyKind.ENUM_ENTRIES + diff --git a/java/ql/lib/config/semmlecode.dbscheme b/java/ql/lib/config/semmlecode.dbscheme index 7cbc85b1f3e..ecfcf050952 100644 --- a/java/ql/lib/config/semmlecode.dbscheme +++ b/java/ql/lib/config/semmlecode.dbscheme @@ -1219,6 +1219,7 @@ ktSyntheticBody( int kind: int ref // 1: ENUM_VALUES // 2: ENUM_VALUEOF + // 3: ENUM_ENTRIES ) ktLocalFunction( From ca5bc6f224b63d807cbded524a2fce94f41f59cc Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Fri, 16 Jun 2023 13:36:31 +0100 Subject: [PATCH 170/364] Java: Add up/downgrade scripts --- .../old.dbscheme | 1256 +++++++++++++++++ .../semmlecode.dbscheme | 1255 ++++++++++++++++ .../upgrade.properties | 2 + .../old.dbscheme | 1255 ++++++++++++++++ .../semmlecode.dbscheme | 1256 +++++++++++++++++ .../upgrade.properties | 2 + 6 files changed, 5026 insertions(+) create mode 100644 java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/old.dbscheme create mode 100644 java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/semmlecode.dbscheme create mode 100644 java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/upgrade.properties create mode 100644 java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/old.dbscheme create mode 100644 java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/semmlecode.dbscheme create mode 100644 java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/upgrade.properties diff --git a/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/old.dbscheme b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/old.dbscheme new file mode 100644 index 00000000000..ecfcf050952 --- /dev/null +++ b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/old.dbscheme @@ -0,0 +1,1256 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @classorinterface ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @classorinterface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF + // 3: ENUM_ENTRIES +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/semmlecode.dbscheme b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/semmlecode.dbscheme new file mode 100644 index 00000000000..7cbc85b1f3e --- /dev/null +++ b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/semmlecode.dbscheme @@ -0,0 +1,1255 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @classorinterface ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @classorinterface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/upgrade.properties b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/upgrade.properties new file mode 100644 index 00000000000..5ba64f71d70 --- /dev/null +++ b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/upgrade.properties @@ -0,0 +1,2 @@ +description: Remove ENUM_ENTRIES +compatibility: full diff --git a/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/old.dbscheme b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/old.dbscheme new file mode 100644 index 00000000000..7cbc85b1f3e --- /dev/null +++ b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/old.dbscheme @@ -0,0 +1,1255 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @classorinterface ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @classorinterface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/semmlecode.dbscheme b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/semmlecode.dbscheme new file mode 100644 index 00000000000..ecfcf050952 --- /dev/null +++ b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/semmlecode.dbscheme @@ -0,0 +1,1256 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @classorinterface ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @classorinterface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF + // 3: ENUM_ENTRIES +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/upgrade.properties b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/upgrade.properties new file mode 100644 index 00000000000..47074bcc8ab --- /dev/null +++ b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/upgrade.properties @@ -0,0 +1,2 @@ +description: Add ENUM_ENTRIES +compatibility: full From eb3c33dfe2037924cd78693a4dfd7b8debc9c023 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 19 Jun 2023 11:41:06 +0200 Subject: [PATCH 171/364] python: remove erronous `getACall()` `base` is already the `CallNode` we want. --- python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll b/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll index 0fac6bfaedd..8b80e13d06d 100644 --- a/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll +++ b/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll @@ -100,12 +100,7 @@ private class SummarizedCallableFromModel extends SummarizedCallable { this = type + ";" + path } - override CallCfgNode getACall() { - exists(API::CallNode base | - ModelOutput::resolvedSummaryBase(type, path, base) and - result = base.getACall() - ) - } + override CallCfgNode getACall() { ModelOutput::resolvedSummaryBase(type, path, result) } override ArgumentNode getACallback() { exists(API::Node base | From 0110610c6a25258ec5c03451839604dd13d001b7 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:01:42 +0200 Subject: [PATCH 172/364] Ruby: overhaul API graphs --- .../dataflow/new/internal/TypeTracker.qll | 45 +- ruby/ql/lib/codeql/ruby/ApiGraphs.qll | 1827 +++++++++++------ .../ruby/dataflow/internal/DataFlowPublic.qll | 145 +- .../ruby/frameworks/data/ModelsAsData.qll | 2 +- .../data/internal/ApiGraphModelsSpecific.qll | 54 +- .../ruby/typetracking/ApiGraphShared.qll | 329 +++ .../codeql/ruby/typetracking/TypeTracker.qll | 45 +- .../dataflow/api-graphs/ApiGraphs.expected | 8 +- ...ed => VerifyApiGraphExpectations.expected} | 0 .../api-graphs/VerifyApiGraphExpectations.ql | 77 + .../dataflow/api-graphs/callbacks.rb | 52 +- .../dataflow/api-graphs/chained-access.rb | 31 + .../dataflow/api-graphs/method-callbacks.rb | 64 + .../dataflow/api-graphs/test1.rb | 72 +- .../library-tests/dataflow/api-graphs/use.ql | 88 - .../util/test/InlineExpectationsTest.qll | 13 + 16 files changed, 1940 insertions(+), 912 deletions(-) create mode 100644 ruby/ql/lib/codeql/ruby/typetracking/ApiGraphShared.qll rename ruby/ql/test/library-tests/dataflow/api-graphs/{use.expected => VerifyApiGraphExpectations.expected} (100%) create mode 100644 ruby/ql/test/library-tests/dataflow/api-graphs/VerifyApiGraphExpectations.ql create mode 100644 ruby/ql/test/library-tests/dataflow/api-graphs/chained-access.rb create mode 100644 ruby/ql/test/library-tests/dataflow/api-graphs/method-callbacks.rb delete mode 100644 ruby/ql/test/library-tests/dataflow/api-graphs/use.ql diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll index 25521f5f1a5..74c67b5be78 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll @@ -55,10 +55,9 @@ private module Cached { ) } - pragma[nomagic] - private TypeTracker noContentTypeTracker(boolean hasCall) { - result = MkTypeTracker(hasCall, noContent()) - } + /** Gets a type tracker with no content and the call bit set to the given value. */ + cached + TypeTracker noContentTypeTracker(boolean hasCall) { result = MkTypeTracker(hasCall, noContent()) } /** Gets the summary resulting from appending `step` to type-tracking summary `tt`. */ cached @@ -340,6 +339,8 @@ class StepSummary extends TStepSummary { /** Provides predicates for updating step summaries (`StepSummary`s). */ module StepSummary { + predicate append = Cached::append/2; + /** * Gets the summary that corresponds to having taken a forwards * inter-procedural step from `nodeFrom` to `nodeTo`. @@ -400,6 +401,35 @@ module StepSummary { } deprecated predicate localSourceStoreStep = flowsToStoreStep/3; + + /** Gets the step summary for a level step. */ + StepSummary levelStep() { result = LevelStep() } + + /** Gets the step summary for a call step. */ + StepSummary callStep() { result = CallStep() } + + /** Gets the step summary for a return step. */ + StepSummary returnStep() { result = ReturnStep() } + + /** Gets the step summary for storing into `content`. */ + StepSummary storeStep(TypeTrackerContent content) { result = StoreStep(content) } + + /** Gets the step summary for loading from `content`. */ + StepSummary loadStep(TypeTrackerContent content) { result = LoadStep(content) } + + /** Gets the step summary for loading from `load` and then storing into `store`. */ + StepSummary loadStoreStep(TypeTrackerContent load, TypeTrackerContent store) { + result = LoadStoreStep(load, store) + } + + /** Gets the step summary for a step that only permits contents matched by `filter`. */ + StepSummary withContent(ContentFilter filter) { result = WithContent(filter) } + + /** Gets the step summary for a step that blocks contents matched by `filter`. */ + StepSummary withoutContent(ContentFilter filter) { result = WithoutContent(filter) } + + /** Gets the step summary for a jump step. */ + StepSummary jumpStep() { result = JumpStep() } } /** @@ -545,6 +575,13 @@ module TypeTracker { * Gets a valid end point of type tracking. */ TypeTracker end() { result.end() } + + /** + * INTERNAL USE ONLY. + * + * Gets a valid end point of type tracking with the call bit set to the given value. + */ + predicate end = Cached::noContentTypeTracker/1; } pragma[nomagic] diff --git a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll index 1cf4c445781..aaa80c3c205 100644 --- a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll +++ b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll @@ -1,13 +1,13 @@ /** - * Provides an implementation of _API graphs_, which are an abstract representation of the API - * surface used and/or defined by a code base. + * Provides an implementation of _API graphs_, which allow efficient modelling of how a given + * value is used the code base or how values produced by the code base are consumed by a library. * - * The nodes of the API graph represent definitions and uses of API components. The edges are - * directed and labeled; they specify how the components represented by nodes relate to each other. + * See `API::Node` for more details. */ private import codeql.ruby.AST private import codeql.ruby.DataFlow +private import codeql.ruby.typetracking.ApiGraphShared private import codeql.ruby.typetracking.TypeTracker private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific private import codeql.ruby.controlflow.CfgNodes @@ -19,85 +19,140 @@ private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatc */ module API { /** - * A node in the API graph, representing a value that has crossed the boundary between this - * codebase and an external library (or in general, any external codebase). + * A node in the API graph, that is, a value that can be tracked interprocedurally. * - * ### Basic usage + * The API graph is a graph for tracking values of certain types in a way that accounts for inheritance + * and interprocedural data flow. * * API graphs are typically used to identify "API calls", that is, calls to an external function * whose implementation is not necessarily part of the current codebase. * + * ### Basic usage + * * The most basic use of API graphs is typically as follows: * 1. Start with `API::getTopLevelMember` for the relevant library. * 2. Follow up with a chain of accessors such as `getMethod` describing how to get to the relevant API function. - * 3. Map the resulting API graph nodes to data-flow nodes, using `asSource` or `asSink`. + * 3. Map the resulting API graph nodes to data-flow nodes, using `asSource`, `asSink`, or `asCall`. * - * For example, a simplified way to get arguments to `Foo.bar` would be - * ```ql - * API::getTopLevelMember("Foo").getMethod("bar").getParameter(0).asSink() + * The following examples demonstrate how to identify the expression `x` in various basic cases: + * ```rb + * # API::getTopLevelMember("Foo").getMethod("bar").getArgument(0).asSink() + * Foo.bar(x) + * + * # API::getTopLevelMember("Foo").getMethod("bar").getKeywordArgument("foo").asSink() + * Foo.bar(foo: x) + * + * # API::getTopLevelMember("Foo").getInstance().getMethod("bar").getArgument(0).asSink() + * Foo.new.bar(x) + * + * Foo.bar do |x| # API::getTopLevelMember("Foo").getMethod("bar").getBlock().getParameter(0).asSource() + * end * ``` * - * The most commonly used accessors are `getMember`, `getMethod`, `getParameter`, and `getReturn`. + * ### Data flow * - * ### API graph nodes + * The members predicates on this class generally take inheritance and data flow into account. * - * There are two kinds of nodes in the API graphs, distinguished by who is "holding" the value: - * - **Use-nodes** represent values held by the current codebase, which came from an external library. - * (The current codebase is "using" a value that came from the library). - * - **Def-nodes** represent values held by the external library, which came from this codebase. - * (The current codebase "defines" the value seen by the library). - * - * API graph nodes are associated with data-flow nodes in the current codebase. - * (Since external libraries are not part of the database, there is no way to associate with concrete - * data-flow nodes from the external library). - * - **Use-nodes** are associated with data-flow nodes where a value enters the current codebase, - * such as the return value of a call to an external function. - * - **Def-nodes** are associated with data-flow nodes where a value leaves the current codebase, - * such as an argument passed in a call to an external function. - * - * - * ### Access paths and edge labels - * - * Nodes in the API graph are associated with a set of access paths, describing a series of operations - * that may be performed to obtain that value. - * - * For example, the access path `API::getTopLevelMember("Foo").getMethod("bar")` represents the action of - * reading the top-level constant `Foo` and then accessing the method `bar` on the resulting object. - * It would be associated with a call such as `Foo.bar()`. - * - * Each edge in the graph is labelled by such an "operation". For an edge `A->B`, the type of the `A` node - * determines who is performing the operation, and the type of the `B` node determines who ends up holding - * the result: - * - An edge starting from a use-node describes what the current codebase is doing to a value that - * came from a library. - * - An edge starting from a def-node describes what the external library might do to a value that - * came from the current codebase. - * - An edge ending in a use-node means the result ends up in the current codebase (at its associated data-flow node). - * - An edge ending in a def-node means the result ends up in external code (its associated data-flow node is - * the place where it was "last seen" in the current codebase before flowing out) - * - * Because the implementation of the external library is not visible, it is not known exactly what operations - * it will perform on values that flow there. Instead, the edges starting from a def-node are operations that would - * lead to an observable effect within the current codebase; without knowing for certain if the library will actually perform - * those operations. (When constructing these edges, we assume the library is somewhat well-behaved). - * - * For example, given this snippet: + * The following example demonstrate a case where data flow was used to find the sink `x`: * ```ruby - * Foo.bar(->(x) { doSomething(x) }) + * def doSomething f + * f.bar(x) # API::getTopLevelMember("Foo").getInstance().getMethod("bar").getArgument(0).asSink() + * end + * doSomething Foo.new * ``` - * A callback is passed to the external function `Foo.bar`. We can't know if `Foo.bar` will actually invoke this callback. - * But _if_ the library should decide to invoke the callback, then a value will flow into the current codebase via the `x` parameter. - * For that reason, an edge is generated representing the argument-passing operation that might be performed by `Foo.bar`. - * This edge is going from the def-node associated with the callback to the use-node associated with the parameter `x` of the lambda. + * The call `API::getTopLevelMember("Foo").getInstance()` identifies the `Foo.new` call, and `getMethod("bar")` + * then follows data flow from there to find calls to `bar` where that object flows to the receiver. + * This results in the `f.bar` call. + * + * ### Backward data flow + * + * When inspecting the arguments of a call, the data flow direction is backwards. + * The following example illustrates this when we match the `x` parameter of a block: + * ```ruby + * def doSomething &blk + * Foo.bar &blk + * end + * doSomething do |x| # API::getTopLevelMember("Foo").getMethod("bar").getBlock().getParameter(0).asSource() + * end + * ``` + * When `getParameter(0)` is evaluated, the API graph backtracks the `&blk` argument to the block argument a few + * lines below. As a result, it eventually matches the `x` parameter of that block. + * + * ### Inheritance + * + * When a class or module object is tracked, inheritance is taken into account. + * + * In the following example, a call to `Foo.bar` was found via a subclass of `Foo`, + * because classes inherit singleton methods from their base class: + * ```ruby + * class Subclass < Foo + * def self.doSomething + * bar(x) # API::getTopLevelMember("Foo").getMethod("bar").getArgument(0).asSink() + * end + * end + * ``` + * + * Similarly, instance methods can be found in subclasses, or ancestors of subclases in cases of multiple inheritance: + * ```rb + * module Mixin + * def doSomething + * bar(x) # API::getTopLevelMember("Foo").getInstance().getMethod("bar").getArgument(0).asSink() + * end + * end + * class Subclass < Foo + * include Mixin + * end + * ``` + * The value of `self` in `Mixin#doSomething` is seen as a potential instance of `Foo`, and is thus found by `getTopLevelMember("Foo").getInstance()`. + * This eventually results in finding the call `bar`, due to its implicit `self` receiver, and finally its argument `x` is found as the sink. + * + * ### Backward data flow and classes + * + * When inspecting the arguments of call, and the value flowing into that argument is a user-defined class (or an instance thereof), + * uses of `getMethod` will find method definitions in that class (including inherited ones) rather than finding method calls. + * + * This example illustrates how this can be used to model cases where the library calls a specific named method on a user-defined class: + * ```rb + * class MyClass + * def doSomething + * x # API::getTopLevelMember("Foo").getMethod("bar").getArgument(0).getMethod("doSomething").getReturn().asSink() + * end + * end + * Foo.bar MyClass.new + * ``` + * + * When modeling an external library that is known to call a specific method on a parameter (in this case `doSomething`), this makes + * it possible to find the corresponding method definition in user code. + * + * ### Strict left-to-right evaluation + * + * Most member predicates on this class are intended to be chained, and are always evaluated from left to right, which means + * the caller should restrict the initial set of values. + * + * For example, in the following snippet, we always find the uses of `Foo` before finding calls to `bar`: + * ```ql + * API::getTopLevelMember("Foo").getMethod("bar") + * ``` + * In particular, the implementation will never look for calls to `bar` and work backward from there. + * + * Beware of the footgun that is to use API graphs with an unrestricted receiver: + * ```ql + * API::Node barCall(API::Node base) { + * result = base.getMethod("bar") // Do not do this! + * } + * ``` + * The above predicate does not restrict the receiver, and will thus perform an interprocedural data flow + * search starting at every node in the graph, which is very expensive. */ class Node extends Impl::TApiNode { /** - * Gets a data-flow node where this value may flow after entering the current codebase. + * Gets a data-flow node where this value may flow interprocedurally. * * This is similar to `asSource()` but additionally includes nodes that are transitively reachable by data flow. * See `asSource()` for examples. */ - pragma[inline] + bindingset[this] + pragma[inline_late] DataFlow::Node getAValueReachableFromSource() { result = getAValueReachableFromSourceInline(this) } @@ -119,16 +174,14 @@ module API { * end * ``` */ - pragma[inline] - DataFlow::LocalSourceNode asSource() { - result = pragma[only_bind_out](this).(Node::Internal).asSourceInternal() - } + bindingset[this] + pragma[inline_late] + DataFlow::LocalSourceNode asSource() { result = asSourceInline(this) } /** - * Gets a data-flow node where this value leaves the current codebase and flows into an - * external library (or in general, any external codebase). + * Gets a data-flow node where this value potentially flows into an external library. * - * Concretely, this corresponds to an argument passed to a call to external code. + * This is usually the argument of a call, but can also be the return value of a callback. * * For example: * ```ruby @@ -143,15 +196,425 @@ module API { * }) * ``` */ - DataFlow::Node asSink() { Impl::def(this, result) } + bindingset[this] + pragma[inline_late] + DataFlow::Node asSink() { result = asSinkInline(this) } /** - * Get a data-flow node that transitively flows to an external library (or in general, any external codebase). + * Get a data-flow node that transitively flows to this value, provided that this value corresponds + * to a sink. * * This is similar to `asSink()` but additionally includes nodes that transitively reach a sink by data flow. * See `asSink()` for examples. */ - DataFlow::Node getAValueReachingSink() { result = Impl::trackDefNode(this.asSink()) } + bindingset[this] + pragma[inline_late] + DataFlow::Node getAValueReachingSink() { result = getAValueReachingSinkInline(this) } + + /** + * Gets a module or class referred to by this API node. + * + * For example: + * ```ruby + * module Foo + * class Bar # API::getTopLevelMember("Foo").getMember("Bar").asModule() + * end + * end + * ``` + */ + bindingset[this] + pragma[inline_late] + DataFlow::ModuleNode asModule() { this = Impl::MkModuleObjectDown(result) } + + /** + * Gets the call referred to by this API node. + * + * For example: + * ```ruby + * # API::getTopLevelMember("Foo").getMethod("bar").asCall() + * Foo.bar + * + * class Bar < Foo + * def doSomething + * # API::getTopLevelMember("Foo").getInstance().getMethod("baz").asCall() + * baz + * end + * end + * ``` + */ + bindingset[this] + pragma[inline_late] + DataFlow::CallNode asCall() { this = Impl::MkMethodAccessNode(result) } + + /** + * DEPRECATED. Use `asCall()` instead. + */ + pragma[inline] + deprecated DataFlow::CallNode getCallNode() { this = Impl::MkMethodAccessNode(result) } + + /** + * Gets a module that descends from the value referenced by this API node. + */ + bindingset[this] + pragma[inline_late] + DataFlow::ModuleNode getADescendentModule() { result = this.getAnEpsilonSuccessor().asModule() } + + /** + * Gets a call to a method on the receiver represented by this API node. + * + * This is a shorthand for `getMethod(method).asCall()`, and thus returns a data-flow node + * rather than an API node. + * + * For example: + * ```ruby + * # API::getTopLevelMember("Foo").getAMethodCall("bar") + * Foo.bar + * ``` + */ + pragma[inline] + DataFlow::CallNode getAMethodCall(string method) { + // This predicate is currently not 'inline_late' because 'method' can be an input or output + result = this.getMethod(method).asCall() + } + + /** + * Gets an access to the constant `m` with this value as the base of the access. + * + * For example, the constant `A::B` would be found by `API::getATopLevelMember("A").getMember("B")` + * For example: + * ```ruby + * A::B # API::getATopLevelMember("A").getMember("B") + * + * module A + * class B # API::getATopLevelMember("A").getMember("B") + * end + * end + * ``` + */ + pragma[inline] + Node getMember(string m) { + // This predicate is currently not 'inline_late' because 'm' can be an input or output + Impl::memberEdge(this.getAnEpsilonSuccessor(), m, result) + } + + /** + * Gets an access to a constant with this valeu as the base of the access. + * + * This is equivalent to `getMember(_)` but can be more efficient. + */ + bindingset[this] + pragma[inline_late] + Node getAMember() { Impl::anyMemberEdge(this.getAnEpsilonSuccessor(), result) } + + /** + * Gets a node that may refer to an instance of the module or class represented by this API node. + * + * This includes the following: + * - Calls to `new` on this module or class or a descendent thereof + * - References to `self` in instance methods declared in any ancestor of any descendent of this module or class + * + * For example: + * ```ruby + * A.new # API::getTopLevelMember("A").getInstance() + * + * class B < A + * def m + * self # API::getTopLevelMember("A").getInstance() + * end + * end + * + * B.new # API::getTopLevelMember("A").getInstance() + * + * class C < A + * include Mixin + * end + * module Mixin + * def m + * # Although 'Mixin' is not directly related to 'A', 'self' may refer to an instance of 'A' + * # due to its inclusion in a subclass of 'A'. + * self # API::getTopLevelMember("A").getInstance() + * end + * end + * ``` + */ + bindingset[this] + pragma[inline_late] + Node getInstance() { Impl::instanceEdge(this.getAnEpsilonSuccessor(), result) } + + /** + * Gets a call to `method` with this value as the receiver, or the definition of `method` on + * an object that can reach this sink. + * + * If the receiver represents a module or class object, this includes calls on descendents of that module or class. + * + * For example: + * ```ruby + * # API::getTopLevelMember("Foo").getMethod("bar") + * Foo.bar + * + * # API::getTopLevelMember("Foo").getInstance().getMethod("bar") + * Foo.new.bar + * + * class B < Foo + * end + * B.bar # API::getTopLevelMember("Foo").getMethod("bar") + * + * class C + * def m # API::getTopLevelMember("Foo").getMethod("bar").getArgument(0).getMethod("m") + * end + * end + * Foo.bar(C.new) + * ``` + */ + pragma[inline] + Node getMethod(string method) { + // TODO: Consider 'getMethodTarget(method)' for looking up method definitions? + // This predicate is currently not 'inline_late' because 'method' can be an input or output + Impl::methodEdge(this.getAnEpsilonSuccessor(), method, result) + } + + /** + * Gets the result of this call, or the return value of this callable. + */ + bindingset[this] + pragma[inline_late] + Node getReturn() { Impl::returnEdge(this.getAnEpsilonSuccessor(), result) } + + /** + * Gets the result of a call to `method` with this value as the receiver, or the return value of `method` defined on + * an object that can reach this sink. + * + * This is a shorthand for `getMethod(method).getReturn()`. + */ + pragma[inline] + Node getReturn(string method) { + // This predicate is currently not 'inline_late' because 'method' can be an input or output + result = this.getMethod(method).getReturn() + } + + /** + * Gets the `n`th positional argument to this call. + * + * For example, this would get `x` in the following snippet: + * ```ruby + * Foo.bar(x) # API::getTopLevelMember("Foo").getMethod("bar").getArgument(0) + * ``` + */ + pragma[inline] + Node getArgument(int n) { + // This predicate is currently not 'inline_late' because 'n' can be an input or output + Impl::positionalArgumentEdge(this, n, result) + } + + /** + * Gets the given keyword argument to this call. + * + * For example, this would get `x` in the following snippet: + * ```ruby + * Foo.bar(baz: x) # API::getTopLevelMember("Foo").getMethod("bar").getKeywordArgument("baz") + * ``` + */ + pragma[inline] + Node getKeywordArgument(string name) { + // This predicate is currently not 'inline_late' because 'name' can be an input or output + Impl::keywordArgumentEdge(this, name, result) + } + + /** + * Gets the block parameter of a callable that can reach this sink. + * + * For example, this would get the `&blk` in the following snippet: + * ```ruby + * # API::getTopLevelMember("Foo").getMethod("bar").getArgument(0).getBlockParameter() + * Foo.bar(->(&blk) {}) + * end + * ``` + */ + bindingset[this] + pragma[inline_late] + Node getBlockParameter() { Impl::blockParameterEdge(this.getAnEpsilonSuccessor(), result) } + + /** + * Gets the `n`th positional parameter of this callable, or the `n`th positional argument to this call. + * + * Note: for historical reasons, this predicate may refer to an argument of a call, but this may change in the future. + * When referring to an argument, it is recommended to use `getArgument(n)` instead. + */ + pragma[inline] + Node getParameter(int n) { + // This predicate is currently not 'inline_late' because 'n' can be an input or output + Impl::positionalParameterOrArgumentEdge(this.getAnEpsilonSuccessor(), n, result) + } + + /** + * Gets the given keyword parameter of this callable, or keyword argument to this call. + * + * Note: for historical reasons, this predicate may refer to an argument of a call, but this may change in the future. + * When referring to an argument, it is recommended to use `getKeywordArgument(n)` instead. + */ + pragma[inline] + Node getKeywordParameter(string name) { + // This predicate is currently not 'inline_late' because 'name' can be an input or output + Impl::keywordParameterOrArgumentEdge(this.getAnEpsilonSuccessor(), name, result) + } + + /** + * Gets the block argument to this call, or the block parameter of this callable. + * + * Note: this predicate may refer to either an argument or a parameter. When referring to a block parameter, + * it is recommended to use `getBlockParameter()` instead. + * + * For example: + * ```ruby + * Foo.bar do |x| # API::getTopLevelMember("Foo").getMethod("bar").getBlock().getParameter(0) + * end + * ``` + */ + bindingset[this] + pragma[inline_late] + Node getBlock() { Impl::blockParameterOrArgumentEdge(this.getAnEpsilonSuccessor(), result) } + + /** + * Gets the argument passed in argument position `pos` at this call. + */ + pragma[inline] + Node getArgumentAtPosition(DataFlowDispatch::ArgumentPosition pos) { + // This predicate is currently not 'inline_late' because 'pos' can be an input or output + Impl::argumentEdge(pragma[only_bind_out](this), pos, result) // note: no need for epsilon step since 'this' must be a call + } + + /** + * Gets the parameter at position `pos` of this callable. + */ + pragma[inline] + Node getParameterAtPosition(DataFlowDispatch::ParameterPosition pos) { + // This predicate is currently not 'inline_late' because 'pos' can be an input or output + Impl::parameterEdge(this.getAnEpsilonSuccessor(), pos, result) + } + + /** + * Gets a `new` call with this value as the receiver. + */ + bindingset[this] + pragma[inline_late] + DataFlow::ExprNode getAnInstantiation() { result = this.getReturn("new").asSource() } + + /** + * Gets a representative for the `content` of this value. + * + * When possible, it is preferrable to use one of the specialized variants of this predicate, such as `getAnElement`. + * + * Concretely, this gets sources where `content` is read from this value, and as well as sinks where + * `content` is stored onto this value or onto an object that can reach this sink. + */ + pragma[inline] + Node getContent(DataFlow::Content content) { + // This predicate is currently not 'inline_late' because 'content' can be an input or output + Impl::contentEdge(this.getAnEpsilonSuccessor(), content, result) + } + + /** + * Gets a representative for the `contents` of this value. + * + * See `getContent()` for more details. + */ + bindingset[this, contents] + pragma[inline_late] + Node getContents(DataFlow::ContentSet contents) { + // We always use getAStoreContent when generating content edges, and we always use getAReadContent when querying the graph. + result = this.getContent(contents.getAReadContent()) + } + + /** + * Gets a representative for the instance field of the given `name`, which must include the `@` character. + * + * This can be used to find cases where a class accesses the fields used by a base class. + * + * ```ruby + * class A < B + * def m + * @foo # API::getTopLevelMember("B").getInstance().getField("@foo") + * end + * end + * ``` + */ + pragma[inline] + Node getField(string name) { + // This predicate is currently not 'inline_late' because 'name' can be an input or output + Impl::fieldEdge(this.getAnEpsilonSuccessor(), name, result) + } + + /** + * Gets a representative for an arbitrary element of this collection. + * + * For example: + * ```ruby + * Foo.bar.each do |x| # API::getTopLevelMember("Foo").getMethod("bar").getReturn().getAnElement() + * end + * + * Foo.bar[0] # API::getTopLevelMember("Foo").getMethod("bar").getReturn().getAnElement() + * ``` + */ + bindingset[this] + pragma[inline_late] + Node getAnElement() { Impl::elementEdge(this.getAnEpsilonSuccessor(), result) } + + /** + * Gets the data-flow node that gives rise to this node, if any. + */ + DataFlow::Node getInducingNode() { + this = Impl::MkMethodAccessNode(result) or + this = Impl::MkBackwardNode(result, _) or + this = Impl::MkForwardNode(result, _) or + this = Impl::MkSinkNode(result) + } + + /** Gets the location of this node. */ + Location getLocation() { + result = this.getInducingNode().getLocation() + or + exists(DataFlow::ModuleNode mod | + this = Impl::MkModuleObjectDown(mod) + or + this = Impl::MkModuleInstanceUp(mod) + | + result = mod.getLocation() + ) + or + this instanceof RootNode and + result instanceof EmptyLocation + } + + /** + * Gets a textual representation of this element. + */ + string toString() { none() } + + /** + * Gets a node representing a (direct or indirect) subclass of the class represented by this node. + * ```rb + * class A; end + * class B < A; end + * class C < B; end + * ``` + * In the example above, `getMember("A").getASubclass()` will return uses of `A`, `B` and `C`. + */ + pragma[inline] + deprecated Node getASubclass() { result = this } + + /** + * Gets a node representing a direct subclass of the class represented by this node. + * ```rb + * class A; end + * class B < A; end + * class C < B; end + * ``` + * In the example above, `getMember("A").getAnImmediateSubclass()` will return uses of `B` only. + */ + pragma[inline] + deprecated Node getAnImmediateSubclass() { + result = this.asModule().getAnImmediateDescendent().trackModule() + } /** DEPRECATED. This predicate has been renamed to `getAValueReachableFromSource()`. */ deprecated DataFlow::Node getAUse() { result = this.getAValueReachableFromSource() } @@ -166,326 +629,143 @@ module API { deprecated DataFlow::Node getAValueReachingRhs() { result = this.getAValueReachingSink() } /** - * Gets a call to a method on the receiver represented by this API component. - */ - pragma[inline] - DataFlow::CallNode getAMethodCall(string method) { result = this.getReturn(method).asSource() } - - /** - * Gets a node representing member `m` of this API component. + * DEPRECATED. API graph nodes are no longer associated with specific paths. * - * For example, a member can be: - * - * - A submodule of a module - * - An attribute of an object - */ - pragma[inline] - Node getMember(string m) { - result = pragma[only_bind_out](this).(Node::Internal).getMemberInternal(m) - } - - /** - * Gets a node representing a member of this API component where the name of the member may - * or may not be known statically. - */ - cached - Node getAMember() { - Impl::forceCachingInSameStage() and - result = this.getASuccessor(Label::member(_)) - } - - /** - * Gets a node representing an instance of this API component, that is, an object whose - * constructor is the function represented by this node. - * - * For example, if this node represents a use of some class `A`, then there might be a node - * representing instances of `A`, typically corresponding to expressions `A.new` at the - * source level. - * - * This predicate may have multiple results when there are multiple constructor calls invoking this API component. - * Consider using `getAnInstantiation()` if there is a need to distinguish between individual constructor calls. - */ - pragma[inline] - Node getInstance() { result = this.getASubclass().getReturn("new") } - - /** - * Gets a node representing a call to `method` on the receiver represented by this node. - */ - pragma[inline] - MethodAccessNode getMethod(string method) { - result = pragma[only_bind_out](this).(Node::Internal).getMethodInternal(method) - } - - /** - * Gets a node representing the result of this call. - */ - pragma[inline] - Node getReturn() { result = pragma[only_bind_out](this).(Node::Internal).getReturnInternal() } - - /** - * Gets a node representing the result of calling a method on the receiver represented by this node. - */ - pragma[inline] - Node getReturn(string method) { result = this.getMethod(method).getReturn() } - - /** Gets an API node representing the `n`th positional parameter. */ - cached - Node getParameter(int n) { - Impl::forceCachingInSameStage() and - result = this.getASuccessor(Label::parameter(n)) - } - - /** Gets an API node representing the given keyword parameter. */ - cached - Node getKeywordParameter(string name) { - Impl::forceCachingInSameStage() and - result = this.getASuccessor(Label::keywordParameter(name)) - } - - /** Gets an API node representing the block parameter. */ - cached - Node getBlock() { - Impl::forceCachingInSameStage() and - result = this.getASuccessor(Label::blockParameter()) - } - - /** - * Gets a `new` call to the function represented by this API component. - */ - pragma[inline] - DataFlow::ExprNode getAnInstantiation() { result = this.getInstance().asSource() } - - /** - * Gets a node representing a (direct or indirect) subclass of the class represented by this node. - * ```rb - * class A; end - * class B < A; end - * class C < B; end - * ``` - * In the example above, `getMember("A").getASubclass()` will return uses of `A`, `B` and `C`. - */ - Node getASubclass() { result = this.getAnImmediateSubclass*() } - - /** - * Gets a node representing a direct subclass of the class represented by this node. - * ```rb - * class A; end - * class B < A; end - * class C < B; end - * ``` - * In the example above, `getMember("A").getAnImmediateSubclass()` will return uses of `B` only. - */ - cached - Node getAnImmediateSubclass() { - Impl::forceCachingInSameStage() and result = this.getASuccessor(Label::subclass()) - } - - /** - * Gets a node representing the `content` stored on the base object. - */ - cached - Node getContent(DataFlow::Content content) { - Impl::forceCachingInSameStage() and - result = this.getASuccessor(Label::content(content)) - } - - /** - * Gets a node representing the `contents` stored on the base object. - */ - pragma[inline] - Node getContents(DataFlow::ContentSet contents) { - // We always use getAStoreContent when generating the graph, and we always use getAReadContent when querying the graph. - result = this.getContent(contents.getAReadContent()) - } - - /** Gets a node representing the instance field of the given `name`, which must include the `@` character. */ - cached - Node getField(string name) { - Impl::forceCachingInSameStage() and - result = this.getContent(DataFlowPrivate::TFieldContent(name)) - } - - /** Gets a node representing an element of this collection (known or unknown). */ - cached - Node getAnElement() { - Impl::forceCachingInSameStage() and - result = this.getContents(any(DataFlow::ContentSet set | set.isAnyElement())) - } - - /** * Gets a string representation of the lexicographically least among all shortest access paths * from the root to this node. */ - string getPath() { - result = min(string p | p = this.getAPath(Impl::distanceFromRoot(this)) | p) - } + deprecated string getPath() { none() } /** + * DEPRECATED. Use label-specific predicates in this class, such as `getMember`, instead of using `getASuccessor`. + * * Gets a node such that there is an edge in the API graph between this node and the other * one, and that edge is labeled with `lbl`. */ - Node getASuccessor(Label::ApiLabel lbl) { Impl::edge(this, lbl, result) } + pragma[inline] + deprecated Node getASuccessor(Label::ApiLabel lbl) { + labelledEdge(this.getAnEpsilonSuccessor(), lbl, result) + } /** + * DEPRECATED. API graphs no longer support backward traversal of edges. If possible use `.backtrack()` to get + * a node intended for backtracking. + * * Gets a node such that there is an edge in the API graph between that other node and * this one, and that edge is labeled with `lbl` */ - Node getAPredecessor(Label::ApiLabel lbl) { this = result.getASuccessor(lbl) } + deprecated Node getAPredecessor(Label::ApiLabel lbl) { this = result.getASuccessor(lbl) } /** + * DEPRECATED. API graphs no longer support backward traversal of edges. If possible use `.backtrack()` to get + * a node intended for backtracking. + * * Gets a node such that there is an edge in the API graph between this node and the other * one. */ - Node getAPredecessor() { result = this.getAPredecessor(_) } + deprecated Node getAPredecessor() { result = this.getAPredecessor(_) } /** * Gets a node such that there is an edge in the API graph between that other node and * this one. */ - Node getASuccessor() { result = this.getASuccessor(_) } + pragma[inline] + deprecated Node getASuccessor() { result = this.getASuccessor(_) } - /** - * Gets the data-flow node that gives rise to this node, if any. - */ - DataFlow::Node getInducingNode() { - this = Impl::MkUse(result) - or - this = Impl::MkDef(result) - or - this = Impl::MkMethodAccessNode(result) - } + /** DEPRECATED. API graphs are no longer associated with a depth. */ + deprecated int getDepth() { none() } - /** Gets the location of this node. */ - Location getLocation() { - result = this.getInducingNode().getLocation() - or - exists(DataFlow::ModuleNode mod | - this = Impl::MkModuleObject(mod) and - result = mod.getLocation() - ) - or - // For nodes that do not have a meaningful location, `path` is the empty string and all other - // parameters are zero. - not exists(this.getInducingNode()) and - result instanceof EmptyLocation - } - - /** - * Gets a textual representation of this element. - */ - string toString() { none() } - - /** - * Gets a path of the given `length` from the root to this node. - */ - private string getAPath(int length) { - this instanceof Impl::MkRoot and - length = 0 and - result = "" - or - exists(Node pred, Label::ApiLabel lbl, string predpath | - Impl::edge(pred, lbl, this) and - predpath = pred.getAPath(length - 1) and - exists(string dot | if length = 1 then dot = "" else dot = "." | - result = predpath + dot + lbl and - // avoid producing strings longer than 1MB - result.length() < 1000 * 1000 - ) - ) and - length in [1 .. Impl::distanceFromRoot(this)] - } - - /** Gets the shortest distance from the root to this node in the API graph. */ - int getDepth() { result = Impl::distanceFromRoot(this) } + pragma[inline] + private Node getAnEpsilonSuccessor() { result = getAnEpsilonSuccessorInline(this) } } - /** Companion module to the `Node` class. */ - module Node { - /** - * INTERNAL USE ONLY. - * - * An API node, with some internal predicates exposed. - */ - class Internal extends Node { - /** - * INTERNAL USE ONLY. - * - * Same as `asSource()` but without join-order hints. - */ - cached - DataFlow::LocalSourceNode asSourceInternal() { - Impl::forceCachingInSameStage() and - Impl::use(this, result) - } + /** DEPRECATED. Use `API::root()` to access the root node. */ + deprecated class Root = RootNode; - /** - * Same as `getMember` but without join-order hints. - */ - cached - Node getMemberInternal(string m) { - Impl::forceCachingInSameStage() and - result = this.getASuccessor(Label::member(m)) - } + /** DEPRECATED. A node corresponding to the use of an API component. */ + deprecated class Use = ForwardNode; - /** - * Same as `getMethod` but without join-order hints. - */ - cached - MethodAccessNode getMethodInternal(string method) { - Impl::forceCachingInSameStage() and - result = this.getASubclass().getASuccessor(Label::method(method)) - } - - /** - * INTERNAL USE ONLY. - * - * Same as `getReturn()` but without join-order hints. - */ - cached - Node getReturnInternal() { - Impl::forceCachingInSameStage() and result = this.getASuccessor(Label::return()) - } - } - } - - bindingset[node] - pragma[inline_late] - private DataFlow::Node getAValueReachableFromSourceInline(Node node) { - exists(DataFlow::LocalSourceNode src, DataFlow::LocalSourceNode dst | - Impl::use(node, pragma[only_bind_into](src)) and - pragma[only_bind_into](dst) = Impl::trackUseNode(src) and - dst.flowsTo(result) - ) - } + /** DEPRECATED. A node corresponding to a value escaping into an API component. */ + deprecated class Def = SinkNode; /** The root node of an API graph. */ - class Root extends Node, Impl::MkRoot { - override string toString() { result = "root" } + private class RootNode extends Node, Impl::MkRoot { + override string toString() { result = "Root()" } } - private string tryGetPath(Node node) { - result = node.getPath() - or - not exists(node.getPath()) and - result = "with no path" + /** A node representing a given type-tracking state when tracking forwards. */ + private class ForwardNode extends Node, Impl::MkForwardNode { + private DataFlow::LocalSourceNode node; + private TypeTracker tracker; + + ForwardNode() { this = Impl::MkForwardNode(node, tracker) } + + override string toString() { + if tracker.start() + then result = "ForwardNode(" + node + ")" + else result = "ForwardNode(" + node + ", " + tracker + ")" + } } - /** A node corresponding to the use of an API component. */ - class Use extends Node, Impl::MkUse { - override string toString() { result = "Use " + tryGetPath(this) } + /** A node representing a given type-tracking state when tracking backwards. */ + private class BackwardNode extends Node, Impl::MkBackwardNode { + private DataFlow::LocalSourceNode node; + private TypeTracker tracker; + + BackwardNode() { this = Impl::MkBackwardNode(node, tracker) } + + override string toString() { + if tracker.start() + then result = "BackwardNode(" + node + ")" + else result = "BackwardNode(" + node + ", " + tracker + ")" + } } - /** A node corresponding to a value escaping into an API component. */ - class Def extends Node, Impl::MkDef { - override string toString() { result = "Def " + tryGetPath(this) } + /** A node representing a module/class object with epsilon edges to its descendents. */ + private class ModuleObjectDownNode extends Node, Impl::MkModuleObjectDown { + /** Gets the module represented by this API node. */ + DataFlow::ModuleNode getModule() { this = Impl::MkModuleObjectDown(result) } + + override string toString() { result = "ModuleObjectDown(" + this.getModule() + ")" } + } + + /** A node representing a module/class object with epsilon edges to its ancestors. */ + private class ModuleObjectUpNode extends Node, Impl::MkModuleObjectUp { + /** Gets the module represented by this API node. */ + DataFlow::ModuleNode getModule() { this = Impl::MkModuleObjectUp(result) } + + override string toString() { result = "ModuleObjectUp(" + this.getModule() + ")" } + } + + /** A node representing instances of a module/class with epsilon edges to its ancestors. */ + private class ModuleInstanceUpNode extends Node, Impl::MkModuleInstanceUp { + /** Gets the module whose instances are represented by this API node. */ + DataFlow::ModuleNode getModule() { this = Impl::MkModuleInstanceUp(result) } + + override string toString() { result = "ModuleInstanceUp(" + this.getModule() + ")" } + } + + /** A node representing instances of a module/class with epsilon edges to its descendents. */ + private class ModuleInstanceDownNode extends Node, Impl::MkModuleInstanceDown { + /** Gets the module whose instances are represented by this API node. */ + DataFlow::ModuleNode getModule() { this = Impl::MkModuleInstanceDown(result) } + + override string toString() { result = "ModuleInstanceDown(" + this.getModule() + ")" } } /** A node corresponding to the method being invoked at a method call. */ class MethodAccessNode extends Node, Impl::MkMethodAccessNode { - override string toString() { result = "MethodAccessNode " + tryGetPath(this) } + override string toString() { result = "MethodAccessNode(" + this.asCall() + ")" } + } - /** Gets the call node corresponding to this method access. */ - DataFlow::CallNode getCallNode() { this = Impl::MkMethodAccessNode(result) } + /** + * A node corresponding to an argument, right-hand side of a store, or return value from a callable. + * + * Such a node may serve as the starting-point of backtracking, and has epsilon edges going + * the backward nodes corresponding to `getALocalSource`. + */ + private class SinkNode extends Node, Impl::MkSinkNode { + override string toString() { result = "SinkNode(" + this.getInducingNode() + ")" } } /** @@ -499,6 +779,8 @@ module API { * additional entry points may be added by extending this class. */ abstract class EntryPoint extends string { + // Note: this class can be deprecated in Ruby, but is still referenced by shared code in ApiGraphModels.qll, + // where it can't be removed since other languages are still dependent on the EntryPoint class. bindingset[this] EntryPoint() { any() } @@ -518,7 +800,7 @@ module API { DataFlow::CallNode getACall() { none() } /** Gets an API-node for this entry point. */ - API::Node getANode() { result = root().getASuccessor(Label::entryPoint(this)) } + API::Node getANode() { Impl::entryPointEdge(this, result) } } // Ensure all entry points are imported from ApiGraphs.qll @@ -527,88 +809,301 @@ module API { } /** Gets the root node. */ - Root root() { any() } + Node root() { result instanceof RootNode } /** - * Gets a node corresponding to a top-level member `m` (typically a module). + * Gets an access to the top-level constant `name`. * - * This is equivalent to `root().getAMember("m")`. - * - * Note: You should only use this predicate for top level modules or classes. If you want nodes corresponding to a nested module or class, - * you should use `.getMember` on the parent module/class. For example, for nodes corresponding to the class `Gem::Version`, + * To access nested constants, use `getMember()` on the resulting node. For example, for nodes corresponding to the class `Gem::Version`, * use `getTopLevelMember("Gem").getMember("Version")`. */ - cached - Node getTopLevelMember(string m) { - Impl::forceCachingInSameStage() and result = root().(Node::Internal).getMemberInternal(m) - } + pragma[inline] + Node getTopLevelMember(string name) { Impl::topLevelMember(name, result) } /** - * Provides the actual implementation of API graphs, cached for performance. - * - * Ideally, we'd like nodes to correspond to (global) access paths, with edge labels - * corresponding to extending the access path by one element. We also want to be able to map - * nodes to their definitions and uses in the data-flow graph, and this should happen modulo - * (inter-procedural) data flow. - * - * This, however, is not easy to implement, since access paths can have unbounded length - * and we need some way of recognizing cycles to avoid non-termination. Unfortunately, expressing - * a condition like "this node hasn't been involved in constructing any predecessor of - * this node in the API graph" without negative recursion is tricky. - * - * So instead most nodes are directly associated with a data-flow node, representing - * either a use or a definition of an API component. This ensures that we only have a finite - * number of nodes. However, we can now have multiple nodes with the same access - * path, which are essentially indistinguishable for a client of the API. - * - * On the other hand, a single node can have multiple access paths (which is, of - * course, unavoidable). We pick as canonical the alphabetically least access path with - * shortest length. + * Gets an unqualified call at the top-level with the given method name. */ - cached - private module Impl { - cached - predicate forceCachingInSameStage() { any() } + pragma[inline] + MethodAccessNode getTopLevelCall(string name) { Impl::toplevelCall(name, result) } - cached - predicate forceCachingBackref() { - 1 = 1 + pragma[nomagic] + private predicate isReachable(DataFlow::LocalSourceNode node, TypeTracker t) { + t.start() and exists(node) + or + exists(DataFlow::LocalSourceNode prev, TypeTracker t2 | + isReachable(prev, t2) and + node = prev.track(t2, t) and + notSelfParameter(node) + ) + } + + bindingset[node] + pragma[inline_late] + private predicate notSelfParameter(DataFlow::Node node) { + not node instanceof DataFlow::SelfParameterNode + } + + private module SharedArg implements ApiGraphSharedSig { + class ApiNode = Node; + + ApiNode getForwardNode(DataFlow::LocalSourceNode node, TypeTracker t) { + result = Impl::MkForwardNode(node, t) + } + + ApiNode getBackwardNode(DataFlow::LocalSourceNode node, TypeTracker t) { + result = Impl::MkBackwardNode(node, t) + } + + ApiNode getSinkNode(DataFlow::Node node) { result = Impl::MkSinkNode(node) } + + pragma[nomagic] + predicate specificEpsilonEdge(ApiNode pred, ApiNode succ) { + exists(DataFlow::ModuleNode mod | + moduleReferenceEdge(mod, pred, succ) + or + moduleInheritanceEdge(mod, pred, succ) + or + pred = getForwardEndNode(getSuperClassNode(mod)) and + succ = Impl::MkModuleObjectDown(mod) + ) or - exists(getTopLevelMember(_)) + implicitCallEdge(pred, succ) or - exists( - any(Node n) - .(Node::Internal) - .getMemberInternal("foo") - .getAMember() - .(Node::Internal) - .getMethodInternal("foo") - .(Node::Internal) - .getReturnInternal() - .getParameter(0) - .getKeywordParameter("foo") - .getBlock() - .getAnImmediateSubclass() - .getContent(_) - .getField(_) - .getAnElement() - .(Node::Internal) - .asSourceInternal() + exists(DataFlow::HashLiteralNode splat | hashSplatEdge(splat, pred, succ)) + } + + /** + * Holds if the epsilon edge `pred -> succ` should be generated, to handle inheritance relations of `mod`. + */ + pragma[inline] + private predicate moduleInheritanceEdge(DataFlow::ModuleNode mod, ApiNode pred, ApiNode succ) { + pred = Impl::MkModuleObjectDown(mod) and + succ = Impl::MkModuleObjectDown(mod.getAnImmediateDescendent()) + or + pred = Impl::MkModuleInstanceDown(mod) and + succ = Impl::MkModuleInstanceDown(mod.getAnImmediateDescendent()) + or + exists(DataFlow::ModuleNode ancestor | + ancestor = mod.getAnImmediateAncestor() and + // Restrict flow back to Object to avoid spurious flow for methods that happen + // to exist on Object, such as top-level methods. + not ancestor.getQualifiedName() = "Object" + | + pred = Impl::MkModuleInstanceUp(mod) and + succ = Impl::MkModuleInstanceUp(ancestor) + or + pred = Impl::MkModuleObjectUp(mod) and + succ = Impl::MkModuleObjectUp(ancestor) + ) + or + // Due to multiple inheritance, allow upwards traversal after downward traversal, + // so we can detect calls sideways in the hierarchy. + // Note that a similar case does not exist for ModuleObject since singleton methods are only inherited + // from the superclass, and there can only be one superclass. + pred = Impl::MkModuleInstanceDown(mod) and + succ = Impl::MkModuleInstanceUp(mod) + } + + /** + * Holds if the epsilon `pred -> succ` be generated, to associate `mod` with its references in the codebase. + */ + bindingset[mod] + pragma[inline_late] + private predicate moduleReferenceEdge(DataFlow::ModuleNode mod, ApiNode pred, ApiNode succ) { + pred = Impl::MkModuleObjectDown(mod) and + succ = getForwardStartNode(getAModuleReference(mod)) + or + pred = getBackwardEndNode(getAModuleReference(mod)) and + ( + succ = Impl::MkModuleObjectUp(mod) + or + succ = Impl::MkModuleObjectDown(mod) + ) + or + pred = Impl::MkModuleInstanceUp(mod) and + succ = getAModuleInstanceUseNode(mod) + or + pred = getAModuleInstanceDefNode(mod) and + succ = Impl::MkModuleInstanceUp(mod) + or + pred = getAModuleDescendentInstanceDefNode(mod) and + succ = Impl::MkModuleInstanceDown(mod) + } + + /** + * Holds if the epsilon step `pred -> succ` should be generated to account for the fact that `getMethod("call")` + * may be omitted when dealing with blocks, lambda, or procs. + * + * For example, a block may be invoked by a `yield`, or can be converted to a proc and then invoked via `.call`. + * To simplify this, the implicit proc conversion is seen as a no-op and the `.call` is omitted. + */ + pragma[nomagic] + private predicate implicitCallEdge(ApiNode pred, ApiNode succ) { + // Step from &block parameter to yield call without needing `getMethod("call")`. + exists(DataFlow::MethodNode method | + pred = getForwardEndNode(method.getBlockParameter()) and + succ = Impl::MkMethodAccessNode(method.getABlockCall()) + ) + or + // Step from x -> x.call (the call itself, not its return value), without needing `getMethod("call")`. + exists(DataFlow::CallNode call | + call.getMethodName() = "call" and + pred = getForwardEndNode(getALocalSourceStrict(call.getReceiver())) and + succ = Impl::MkMethodAccessNode(call) + ) + or + exists(DataFlow::ModuleNode mod | + // Step from module/class to its own `call` method without needing `getMethod("call")`. + (pred = Impl::MkModuleObjectDown(mod) or pred = Impl::MkModuleObjectUp(mod)) and + succ = getBackwardEndNode(mod.getOwnSingletonMethod("call")) + or + pred = Impl::MkModuleInstanceUp(mod) and + succ = getBackwardEndNode(mod.getOwnInstanceMethod("call")) ) } + pragma[nomagic] + private DataFlow::Node getHashSplatArgument(DataFlow::HashLiteralNode literal) { + result = DataFlowPrivate::TSynthHashSplatArgumentNode(literal.asExpr()) + } + + /** + * Holds if the epsilon edge `pred -> succ` should be generated to account for the members of a hash literal. + * + * This currently exists because hash literals are desugared to `Hash.[]` calls, whose summary relies on `WithContent`. + * However, `contentEdge` does not currently generate edges for `WithContent` steps. + */ + bindingset[literal] + pragma[inline_late] + private predicate hashSplatEdge(DataFlow::HashLiteralNode literal, ApiNode pred, ApiNode succ) { + exists(TypeTracker t | + pred = Impl::MkForwardNode(getALocalSourceStrict(getHashSplatArgument(literal)), t) and + succ = Impl::MkForwardNode(pragma[only_bind_out](literal), pragma[only_bind_out](t)) + or + succ = Impl::MkBackwardNode(getALocalSourceStrict(getHashSplatArgument(literal)), t) and + pred = Impl::MkBackwardNode(pragma[only_bind_out](literal), pragma[only_bind_out](t)) + ) + } + + pragma[nomagic] + private DataFlow::LocalSourceNode getAModuleReference(DataFlow::ModuleNode mod) { + result = mod.getAnImmediateReference() + or + mod.getAnAncestor().getAnOwnInstanceSelf() = getANodeReachingClassCall(result) + } + + /** + * Gets an API node that may refer to an instance of `mod`. + */ + bindingset[mod] + pragma[inline_late] + private ApiNode getAModuleInstanceUseNode(DataFlow::ModuleNode mod) { + result = getForwardStartNode(mod.getAnOwnInstanceSelf()) + } + + /** + * Gets a node that can be backtracked to an instance of `mod`. + */ + bindingset[mod] + pragma[inline_late] + private ApiNode getAModuleInstanceDefNode(DataFlow::ModuleNode mod) { + result = getBackwardEndNode(mod.getAnImmediateReference().getAMethodCall("new")) + } + + /** + * Gets a node that can be backtracked to an instance of `mod` or any of its descendents. + */ + bindingset[mod] + pragma[inline_late] + private ApiNode getAModuleDescendentInstanceDefNode(DataFlow::ModuleNode mod) { + result = getBackwardEndNode(mod.getAnOwnInstanceSelf()) + } + + /** + * Holds if `superclass` is the superclass of `mod`. + */ + pragma[nomagic] + private DataFlow::LocalSourceNode getSuperClassNode(DataFlow::ModuleNode mod) { + result.getALocalUse().asExpr().getExpr() = + mod.getADeclaration().(ClassDeclaration).getSuperclassExpr() + } + + /** Gets a node that can reach the receiver of the given `.class` call. */ + private DataFlow::LocalSourceNode getANodeReachingClassCall( + DataFlow::CallNode call, TypeBackTracker t + ) { + t.start() and + call.getMethodName() = "class" and + result = getALocalSourceStrict(call.getReceiver()) + or + exists(DataFlow::LocalSourceNode prev, TypeBackTracker t2 | + prev = getANodeReachingClassCall(call, t2) and + result = prev.backtrack(t2, t) and + notSelfParameter(prev) + ) + } + + /** Gets a node that can reach the receiver of the given `.class` call. */ + private DataFlow::LocalSourceNode getANodeReachingClassCall(DataFlow::CallNode call) { + result = getANodeReachingClassCall(call, TypeBackTracker::end()) + } + } + + /** INTERNAL USE ONLY. */ + module Internal { + private module Shared = ApiGraphShared; + + import Shared + + /** Gets the API node corresponding to the module/class object for `mod`. */ + bindingset[mod] + pragma[inline_late] + Node getModuleNode(DataFlow::ModuleNode mod) { result = Impl::MkModuleObjectDown(mod) } + + /** Gets the API node corresponding to instances of `mod`. */ + bindingset[mod] + pragma[inline_late] + Node getModuleInstance(DataFlow::ModuleNode mod) { result = getModuleNode(mod).getInstance() } + } + + private import Internal + import Internal::Public + + cached + private module Impl { cached newtype TApiNode = /** The root of the API graph. */ MkRoot() or /** The method accessed at `call`, synthetically treated as a separate object. */ - MkMethodAccessNode(DataFlow::CallNode call) { isUse(call) } or - /** A use of an API member at the node `nd`. */ - MkUse(DataFlow::Node nd) { isUse(nd) } or - /** A value that escapes into an external library at the node `nd` */ - MkDef(DataFlow::Node nd) { isDef(nd) } or - /** A module object seen as a use node. */ - MkModuleObject(DataFlow::ModuleNode mod) + MkMethodAccessNode(DataFlow::CallNode call) or + /** The module object `mod` with epsilon edges to its ancestors. */ + MkModuleObjectUp(DataFlow::ModuleNode mod) or + /** The module object `mod` with epsilon edges to its descendents. */ + MkModuleObjectDown(DataFlow::ModuleNode mod) or + /** Instances of `mod` with epsilon edges to its ancestors. */ + MkModuleInstanceUp(DataFlow::ModuleNode mod) or + /** Instances of `mod` with epsilon edges to its descendents, and to its upward node. */ + MkModuleInstanceDown(DataFlow::ModuleNode mod) or + /** Intermediate node for following forward data flow. */ + MkForwardNode(DataFlow::LocalSourceNode node, TypeTracker t) { isReachable(node, t) } or + /** Intermediate node for following backward data flow. */ + MkBackwardNode(DataFlow::LocalSourceNode node, TypeTracker t) { isReachable(node, t) } or + MkSinkNode(DataFlow::Node node) { needsSinkNode(node) } + + private predicate needsSinkNode(DataFlow::Node node) { + node instanceof DataFlowPrivate::ArgumentNode + or + TypeTrackerSpecific::basicStoreStep(node, _, _) + or + node = any(DataFlow::CallableNode callable).getAReturnNode() + or + node = any(EntryPoint e).getASink() + } + + bindingset[e] + pragma[inline_late] + private DataFlow::Node getNodeFromExpr(Expr e) { result.asExpr().getExpr() = e } private string resolveTopLevel(ConstantReadAccess read) { result = read.getModule().getQualifiedName() and @@ -616,300 +1111,283 @@ module API { } /** - * Holds if `ref` is a use of a node that should have an incoming edge from the root - * node labeled `lbl` in the API graph (not including those from API::EntryPoint). + * Holds `pred` should have a member edge to `mod`. */ pragma[nomagic] - private predicate useRoot(Label::ApiLabel lbl, DataFlow::Node ref) { - exists(string name, ConstantReadAccess read | - read = ref.asExpr().getExpr() and - lbl = Label::member(read.getName()) + private predicate moduleScope(DataFlow::ModuleNode mod, Node pred, string name) { + exists(Namespace namespace | + name = namespace.getName() and + namespace = mod.getADeclaration() | - name = resolveTopLevel(read) + exists(DataFlow::Node scopeNode | + scopeNode.asExpr().getExpr() = namespace.getScopeExpr() and + pred = getForwardEndNode(getALocalSourceStrict(scopeNode)) + ) or - name = read.getName() and - not exists(resolveTopLevel(read)) and - not exists(read.getScopeExpr()) + not exists(namespace.getScopeExpr()) and + if namespace.hasGlobalScope() or namespace.getEnclosingModule() instanceof Toplevel + then pred = MkRoot() + else pred = MkModuleObjectDown(namespace.getEnclosingModule().getModule()) ) } - /** - * Holds if `ref` is a use of a node that should have an incoming edge labeled `lbl`, - * from a use node that flows to `node`. - */ - private predicate useStep(Label::ApiLabel lbl, DataFlow::Node node, DataFlow::Node ref) { - // // Referring to an attribute on a node that is a use of `base`: - // pred = `Rails` part of `Rails::Whatever` - // lbl = `Whatever` - // ref = `Rails::Whatever` - exists(ExprNodes::ConstantAccessCfgNode c, ConstantReadAccess read | - not exists(resolveTopLevel(read)) and - node.asExpr() = c.getScopeExpr() and - lbl = Label::member(read.getName()) and - ref.asExpr() = c and - read = c.getExpr() - ) - or - exists(TypeTrackerSpecific::TypeTrackerContent c | - TypeTrackerSpecific::basicLoadStep(node, ref, c) and - lbl = Label::content(c.getAStoreContent()) and - not c.isSingleton(any(DataFlow::Content::AttributeNameContent k)) - ) - // note: method calls are not handled here as there is no DataFlow::Node for the intermediate MkMethodAccessNode API node - } - - /** - * Holds if `rhs` is a definition of a node that should have an incoming edge labeled `lbl`, - * from a def node that is reachable from `node`. - */ - private predicate defStep(Label::ApiLabel lbl, DataFlow::Node node, DataFlow::Node rhs) { - exists(TypeTrackerSpecific::TypeTrackerContent c | - TypeTrackerSpecific::basicStoreStep(rhs, node, c) and - lbl = Label::content(c.getAStoreContent()) - ) - } - - pragma[nomagic] - private predicate isUse(DataFlow::Node nd) { - useRoot(_, nd) - or - exists(DataFlow::Node node | - useCandFwd().flowsTo(node) and - useStep(_, node, nd) - ) - or - useCandFwd().flowsTo(nd.(DataFlow::CallNode).getReceiver()) - or - parameterStep(_, defCand(), nd) - or - nd = any(EntryPoint entry).getASource() - or - nd = any(EntryPoint entry).getACall() - } - - /** - * Holds if `ref` is a use of node `nd`. - */ cached - predicate use(TApiNode nd, DataFlow::Node ref) { - nd = MkUse(ref) + predicate memberEdge(Node pred, string name, Node succ) { + exists(ConstantReadAccess read | succ = getForwardStartNode(getNodeFromExpr(read)) | + name = resolveTopLevel(read) and + pred = MkRoot() + or + not exists(resolveTopLevel(read)) and + not exists(read.getScopeExpr()) and + name = read.getName() and + pred = MkRoot() + or + pred = getForwardEndNode(getALocalSourceStrict(getNodeFromExpr(read.getScopeExpr()))) and + name = read.getName() + ) or exists(DataFlow::ModuleNode mod | - nd = MkModuleObject(mod) and - ref = mod.getAnImmediateReference() + moduleScope(mod, pred, name) and + (succ = MkModuleObjectDown(mod) or succ = MkModuleObjectUp(mod)) ) } - /** - * Holds if `rhs` is a RHS of node `nd`. - */ cached - predicate def(TApiNode nd, DataFlow::Node rhs) { nd = MkDef(rhs) } + predicate topLevelMember(string name, Node node) { memberEdge(root(), name, node) } - /** Gets a node reachable from a use-node. */ - private DataFlow::LocalSourceNode useCandFwd(TypeTracker t) { - t.start() and - isUse(result) - or - exists(TypeTracker t2 | result = useCandFwd(t2).track(t2, t)) - } - - /** Gets a node reachable from a use-node. */ - private DataFlow::LocalSourceNode useCandFwd() { result = useCandFwd(TypeTracker::end()) } - - private predicate isDef(DataFlow::Node rhs) { - // If a call node is relevant as a use-node, treat its arguments as def-nodes - argumentStep(_, useCandFwd(), rhs) - or - defStep(_, defCand(), rhs) - or - rhs = any(EntryPoint entry).getASink() - } - - /** Gets a data flow node that flows to the RHS of a def-node. */ - private DataFlow::LocalSourceNode defCand(TypeBackTracker t) { - t.start() and - exists(DataFlow::Node rhs | - isDef(rhs) and - result = rhs.getALocalSource() - ) - or - exists(TypeBackTracker t2 | result = defCand(t2).backtrack(t2, t)) - } - - /** Gets a data flow node that flows to the RHS of a def-node. */ - private DataFlow::LocalSourceNode defCand() { result = defCand(TypeBackTracker::end()) } - - /** - * Holds if there should be a `lbl`-edge from the given call to an argument. - */ - pragma[nomagic] - private predicate argumentStep( - Label::ApiLabel lbl, DataFlow::CallNode call, DataFlowPrivate::ArgumentNode argument - ) { - exists(DataFlowDispatch::ArgumentPosition argPos | - argument.sourceArgumentOf(call.asExpr(), argPos) and - lbl = Label::getLabelFromArgumentPosition(argPos) - ) - } - - /** - * Holds if there should be a `lbl`-edge from the given callable to a parameter. - */ - pragma[nomagic] - private predicate parameterStep( - Label::ApiLabel lbl, DataFlow::Node callable, DataFlowPrivate::ParameterNodeImpl paramNode - ) { - exists(DataFlowDispatch::ParameterPosition paramPos | - paramNode.isSourceParameterOf(callable.asExpr().getExpr(), paramPos) and - lbl = Label::getLabelFromParameterPosition(paramPos) - ) - } - - /** - * Gets a data-flow node to which `src`, which is a use of an API-graph node, flows. - * - * The flow from `src` to the returned node may be inter-procedural. - */ - private DataFlow::LocalSourceNode trackUseNode(DataFlow::LocalSourceNode src, TypeTracker t) { - result = src and - isUse(src) and - t.start() - or - exists(TypeTracker t2 | - result = trackUseNode(src, t2).track(t2, t) and - not result instanceof DataFlow::SelfParameterNode - ) - } - - /** - * Gets a data-flow node to which `src`, which is a use of an API-graph node, flows. - * - * The flow from `src` to the returned node may be inter-procedural. - */ cached - DataFlow::LocalSourceNode trackUseNode(DataFlow::LocalSourceNode src) { - result = trackUseNode(src, TypeTracker::end()) - } - - /** Gets a data flow node reaching the RHS of the given def node. */ - private DataFlow::LocalSourceNode trackDefNode(DataFlow::Node rhs, TypeBackTracker t) { - t.start() and - isDef(rhs) and - result = rhs.getALocalSource() - or - exists(TypeBackTracker t2, DataFlow::LocalSourceNode mid | - mid = trackDefNode(rhs, t2) and - not mid instanceof DataFlow::SelfParameterNode and - result = mid.backtrack(t2, t) + predicate toplevelCall(string name, Node node) { + exists(DataFlow::CallNode call | + call.asExpr().getExpr().getCfgScope() instanceof Toplevel and + call.getMethodName() = name and + node = MkMethodAccessNode(call) ) } - /** Gets a data flow node reaching the RHS of the given def node. */ cached - DataFlow::LocalSourceNode trackDefNode(DataFlow::Node rhs) { - result = trackDefNode(rhs, TypeBackTracker::end()) - } + predicate anyMemberEdge(Node pred, Node succ) { memberEdge(pred, _, succ) } - pragma[nomagic] - private predicate useNodeReachesReceiver(DataFlow::Node use, DataFlow::CallNode call) { - trackUseNode(use).flowsTo(call.getReceiver()) - } - - /** - * Holds if `superclass` is the superclass of `mod`. - */ - pragma[nomagic] - private predicate superclassNode(DataFlow::ModuleNode mod, DataFlow::Node superclass) { - superclass.asExpr().getExpr() = mod.getADeclaration().(ClassDeclaration).getSuperclassExpr() - } - - /** - * Holds if there is an edge from `pred` to `succ` in the API graph that is labeled with `lbl`. - */ cached - predicate edge(TApiNode pred, Label::ApiLabel lbl, TApiNode succ) { - /* Every node that is a use of an API component is itself added to the API graph. */ - exists(DataFlow::LocalSourceNode ref | succ = MkUse(ref) | - pred = MkRoot() and - useRoot(lbl, ref) + predicate methodEdge(Node pred, string name, Node succ) { + exists(DataFlow::ModuleNode mod, DataFlow::CallNode call | + // Treat super calls as if they were calls to the module object/instance. + succ = MkMethodAccessNode(call) and + name = call.getMethodName() + | + pred = MkModuleObjectDown(mod) and + call = mod.getAnOwnSingletonMethod().getASuperCall() or - exists(DataFlow::Node node, DataFlow::Node src | - use(pred, src) and - trackUseNode(src).flowsTo(node) and - useStep(lbl, node, ref) - ) - or - exists(DataFlow::Node callback | - def(pred, callback) and - parameterStep(lbl, trackDefNode(callback), ref) - ) - ) - or - exists(DataFlow::Node predNode, DataFlow::Node succNode | - def(pred, predNode) and - succ = MkDef(succNode) and - defStep(lbl, trackDefNode(predNode), succNode) - ) - or - exists(DataFlow::Node predNode, DataFlow::Node superclassNode, DataFlow::ModuleNode mod | - use(pred, predNode) and - trackUseNode(predNode).flowsTo(superclassNode) and - superclassNode(mod, superclassNode) and - succ = MkModuleObject(mod) and - lbl = Label::subclass() + pred = MkModuleInstanceUp(mod) and + call = mod.getAnOwnInstanceMethod().getASuperCall() ) or exists(DataFlow::CallNode call | // from receiver to method call node - exists(DataFlow::Node receiver | - use(pred, receiver) and - useNodeReachesReceiver(receiver, call) and - lbl = Label::method(call.getMethodName()) and - succ = MkMethodAccessNode(call) - ) - or - // from method call node to return and arguments - pred = MkMethodAccessNode(call) and - ( - lbl = Label::return() and - succ = MkUse(call) - or - exists(DataFlow::Node rhs | - argumentStep(lbl, call, rhs) and - succ = MkDef(rhs) - ) - ) + pred = getForwardEndNode(getALocalSourceStrict(call.getReceiver())) and + succ = MkMethodAccessNode(call) and + name = call.getMethodName() ) or - exists(EntryPoint entry | - pred = root() and - lbl = Label::entryPoint(entry) - | - succ = MkDef(entry.getASink()) + exists(DataFlow::ModuleNode mod | + (pred = MkModuleObjectDown(mod) or pred = MkModuleObjectUp(mod)) and + succ = getBackwardStartNode(mod.getOwnSingletonMethod(name)) or - succ = MkUse(entry.getASource()) - or - succ = MkMethodAccessNode(entry.getACall()) + pred = MkModuleInstanceUp(mod) and + succ = getBackwardStartNode(mod.getOwnInstanceMethod(name)) ) } - /** - * Holds if there is an edge from `pred` to `succ` in the API graph. - */ - private predicate edge(TApiNode pred, TApiNode succ) { edge(pred, _, succ) } - - /** Gets the shortest distance from the root to `nd` in the API graph. */ cached - int distanceFromRoot(TApiNode nd) = shortestDistances(MkRoot/0, edge/2)(_, nd, result) + predicate contentEdge(Node pred, DataFlow::Content content, Node succ) { + exists( + DataFlow::Node object, DataFlow::Node value, TypeTrackerSpecific::TypeTrackerContent c + | + TypeTrackerSpecific::basicLoadStep(object, value, c) and + content = c.getAStoreContent() and + not c.isSingleton(any(DataFlow::Content::AttributeNameContent k)) and + // `x -> x.foo` with content "foo" + pred = getForwardOrBackwardEndNode(getALocalSourceStrict(object)) and + succ = getForwardStartNode(value) + or + // Based on `object.c = value` generate `object -> value` with content `c` + TypeTrackerSpecific::basicStoreStep(value, object, c) and + content = c.getAStoreContent() and + pred = getForwardOrBackwardEndNode(getALocalSourceStrict(object)) and + succ = MkSinkNode(value) + ) + } + cached + predicate fieldEdge(Node pred, string name, Node succ) { + Impl::contentEdge(pred, DataFlowPrivate::TFieldContent(name), succ) + } + + cached + predicate elementEdge(Node pred, Node succ) { + contentEdge(pred, any(DataFlow::ContentSet set | set.isAnyElement()).getAReadContent(), succ) + } + + cached + predicate parameterEdge(Node pred, DataFlowDispatch::ParameterPosition paramPos, Node succ) { + exists(DataFlowPrivate::ParameterNodeImpl parameter, DataFlow::CallableNode callable | + parameter.isSourceParameterOf(callable.asExpr().getExpr(), paramPos) and + pred = getBackwardEndNode(callable) and + succ = getForwardStartNode(parameter) + ) + } + + cached + predicate argumentEdge(Node pred, DataFlowDispatch::ArgumentPosition argPos, Node succ) { + exists(DataFlow::CallNode call, DataFlowPrivate::ArgumentNode argument | + argument.sourceArgumentOf(call.asExpr(), argPos) and + pred = MkMethodAccessNode(call) and + succ = MkSinkNode(argument) + ) + } + + cached + predicate positionalArgumentEdge(Node pred, int n, Node succ) { + argumentEdge(pred, any(DataFlowDispatch::ArgumentPosition pos | pos.isPositional(n)), succ) + } + + cached + predicate keywordArgumentEdge(Node pred, string name, Node succ) { + argumentEdge(pred, any(DataFlowDispatch::ArgumentPosition pos | pos.isKeyword(name)), succ) + } + + private predicate blockArgumentEdge(Node pred, Node succ) { + argumentEdge(pred, any(DataFlowDispatch::ArgumentPosition pos | pos.isBlock()), succ) + } + + private predicate positionalParameterEdge(Node pred, int n, Node succ) { + parameterEdge(pred, any(DataFlowDispatch::ParameterPosition pos | pos.isPositional(n)), succ) + } + + private predicate keywordParameterEdge(Node pred, string name, Node succ) { + parameterEdge(pred, any(DataFlowDispatch::ParameterPosition pos | pos.isKeyword(name)), succ) + } + + cached + predicate blockParameterEdge(Node pred, Node succ) { + parameterEdge(pred, any(DataFlowDispatch::ParameterPosition pos | pos.isBlock()), succ) + } + + cached + predicate positionalParameterOrArgumentEdge(Node pred, int n, Node succ) { + positionalArgumentEdge(pred, n, succ) + or + positionalParameterEdge(pred, n, succ) + } + + cached + predicate keywordParameterOrArgumentEdge(Node pred, string name, Node succ) { + keywordArgumentEdge(pred, name, succ) + or + keywordParameterEdge(pred, name, succ) + } + + cached + predicate blockParameterOrArgumentEdge(Node pred, Node succ) { + blockArgumentEdge(pred, succ) + or + blockParameterEdge(pred, succ) + } + + pragma[nomagic] + private predicate newCall(DataFlow::LocalSourceNode receiver, DataFlow::CallNode call) { + call = receiver.getAMethodCall("new") + } + + cached + predicate instanceEdge(Node pred, Node succ) { + exists(DataFlow::ModuleNode mod | + pred = MkModuleObjectDown(mod) and + succ = MkModuleInstanceUp(mod) + ) + or + exists(DataFlow::LocalSourceNode receiver, DataFlow::CallNode call | + newCall(receiver, call) and + pred = getForwardEndNode(receiver) and + succ = getForwardStartNode(call) + ) + } + + cached + predicate returnEdge(Node pred, Node succ) { + exists(DataFlow::CallNode call | + pred = MkMethodAccessNode(call) and + succ = getForwardStartNode(call) + ) + or + exists(DataFlow::CallableNode callable | + pred = getBackwardEndNode(callable) and + succ = MkSinkNode(callable.getAReturnNode()) + ) + } + + cached + predicate entryPointEdge(EntryPoint entry, Node node) { + node = MkSinkNode(entry.getASink()) or + node = getForwardStartNode(entry.getASource()) or + node = MkMethodAccessNode(entry.getACall()) + } + } + + /** + * Holds if there is an edge from `pred` to `succ` in the API graph that is labeled with `lbl`. + */ + pragma[nomagic] + deprecated private predicate labelledEdge(Node pred, Label::ApiLabel lbl, Node succ) { + exists(string name | + Impl::memberEdge(pred, name, succ) and + lbl = Label::member(name) + ) + or + exists(string name | + Impl::methodEdge(pred, name, succ) and + lbl = Label::method(name) + ) + or + exists(DataFlow::Content content | + Impl::contentEdge(pred, content, succ) and + lbl = Label::content(content) + ) + or + exists(DataFlowDispatch::ParameterPosition pos | + Impl::parameterEdge(pred, pos, succ) and + lbl = Label::getLabelFromParameterPosition(pos) + ) + or + exists(DataFlowDispatch::ArgumentPosition pos | + Impl::argumentEdge(pred, pos, succ) and + lbl = Label::getLabelFromArgumentPosition(pos) + ) + or + Impl::instanceEdge(pred, succ) and + lbl = Label::instance() + or + Impl::returnEdge(pred, succ) and + lbl = Label::return() + or + exists(EntryPoint entry | + Impl::entryPointEdge(entry, succ) and + pred = root() and + lbl = Label::entryPoint(entry) + ) + } + + /** + * DEPRECATED. Treating the API graph as an explicit labelled graph is deprecated - instead use the methods on `API:Node` directly. + * + * Provides classes modeling the various edges (labels) in the API graph. + */ + deprecated module Label { /** All the possible labels in the API graph. */ - cached - newtype TLabel = + private newtype TLabel = MkLabelMember(string member) { member = any(ConstantReadAccess a).getName() } or MkLabelMethod(string m) { m = any(DataFlow::CallNode c).getMethodName() } or MkLabelReturn() or - MkLabelSubclass() or + MkLabelInstance() or MkLabelKeywordParameter(string name) { any(DataFlowDispatch::ArgumentPosition arg).isKeyword(name) or @@ -923,12 +1401,9 @@ module API { MkLabelBlockParameter() or MkLabelEntryPoint(EntryPoint name) or MkLabelContent(DataFlow::Content content) - } - /** Provides classes modeling the various edges (labels) in the API graph. */ - module Label { /** A label in the API-graph */ - class ApiLabel extends Impl::TLabel { + class ApiLabel extends TLabel { /** Gets a string representation of this label. */ string toString() { result = "???" } } @@ -967,9 +1442,9 @@ module API { override string toString() { result = "getReturn()" } } - /** A label for the subclass relationship. */ - class LabelSubclass extends ApiLabel, MkLabelSubclass { - override string toString() { result = "getASubclass()" } + /** A label for getting instances of a module/class. */ + class LabelInstance extends ApiLabel, MkLabelInstance { + override string toString() { result = "getInstance()" } } /** A label for a keyword parameter. */ @@ -1037,8 +1512,8 @@ module API { /** Gets the `return` edge label. */ LabelReturn return() { any() } - /** Gets the `subclass` edge label. */ - LabelSubclass subclass() { any() } + /** Gets the `instance` edge label. */ + LabelInstance instance() { any() } /** Gets the label representing the given keyword argument/parameter. */ LabelKeywordParameter keywordParameter(string name) { result.getName() = name } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll index c6adcbcbe3a..a142fd1f0fb 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll @@ -6,12 +6,17 @@ private import codeql.ruby.typetracking.TypeTracker private import codeql.ruby.dataflow.SSA private import FlowSummaryImpl as FlowSummaryImpl private import SsaImpl as SsaImpl +private import codeql.ruby.ApiGraphs /** * An element, viewed as a node in a data flow graph. Either an expression * (`ExprNode`) or a parameter (`ParameterNode`). */ class Node extends TNode { + /** Starts backtracking from this node using API graphs. */ + pragma[inline] + API::Node backtrack() { result = API::Internal::getNodeForBacktracking(this) } + /** Gets the expression corresponding to this node, if any. */ CfgNodes::ExprCfgNode asExpr() { result = this.(ExprNode).getExprNode() } @@ -76,6 +81,11 @@ class Node extends TNode { result.asCallableAstNode() = c.asCallable() ) } + + /** Gets the enclosing method, if any. */ + MethodNode getEnclosingMethod() { + result.asCallableAstNode() = this.asExpr().getExpr().getEnclosingMethod() + } } /** A data-flow node corresponding to a call in the control-flow graph. */ @@ -144,6 +154,18 @@ class CallNode extends LocalSourceNode, ExprNode { result.asExpr() = pair.getValue() ) } + + /** + * Gets a potential target of this call, if any. + */ + final CallableNode getATarget() { + result.asCallableAstNode() = this.asExpr().getExpr().(Call).getATarget() + } + + /** + * Holds if this is a `super` call. + */ + final predicate isSuperCall() { this.asExpr().getExpr() instanceof SuperCall } } /** @@ -217,6 +239,10 @@ class SelfParameterNode extends ParameterNode instanceof SelfParameterNodeImpl { class LocalSourceNode extends Node { LocalSourceNode() { isLocalSourceNode(this) } + /** Starts tracking this node forward using API graphs. */ + pragma[inline] + API::Node track() { result = API::Internal::getNodeForForwardTracking(this) } + /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ pragma[inline] predicate flowsTo(Node nodeTo) { hasLocalSource(nodeTo, this) } @@ -359,6 +385,11 @@ private module Cached { ) } + cached + predicate methodHasSuperCall(MethodNode method, CallNode call) { + call.isSuperCall() and method = call.getEnclosingMethod() + } + /** * A place in which a named constant can be looked up during constant lookup. */ @@ -387,6 +418,40 @@ private module Cached { result.asExpr().getExpr() = access } + /** + * Gets a module for which this constant is the reference to an ancestor module. + * + * For example, `M` is the ancestry target of `C` in the following examples: + * ```rb + * class M < C {} + * + * module M + * include C + * end + * + * module M + * prepend C + * end + * ``` + */ + private ModuleNode getAncestryTarget(ConstRef constRef) { result.getAnAncestorExpr() = constRef } + + /** + * Gets a scope in which a constant lookup may access the contents of the module referenced by this constant. + */ + cached + TConstLookupScope getATargetScope(ConstRef constRef) { + forceCachingInSameStage() and + result = MkAncestorLookup(getAncestryTarget(constRef).getAnImmediateDescendent*()) + or + constRef.asConstantAccess() = any(ConstantAccess ac).getScopeExpr() and + result = MkQualifiedLookup(constRef.asConstantAccess()) + or + result = MkNestedLookup(getAncestryTarget(constRef)) + or + result = MkExactLookup(constRef.asConstantAccess().(Namespace).getModule()) + } + cached predicate forceCachingInSameStage() { any() } @@ -1028,6 +1093,33 @@ class ModuleNode instanceof Module { * this predicate. */ ModuleNode getNestedModule(string name) { result = super.getNestedModule(name) } + + /** + * Starts tracking the module object using API graphs. + * + * Concretely, this tracks forward from the following starting points: + * - A constant access that resolves to this module. + * - `self` in the module scope or in a singleton method of the module. + * - A call to `self.class` in an instance method of this module or an ancestor module. + */ + bindingset[this] + pragma[inline] + API::Node trackModule() { result = API::Internal::getModuleNode(this) } + + /** + * Starts tracking instances of this module forward using API graphs. + * + * Concretely, this tracks forward from the following starting points: + * - `self` in instance methods of this module and ancestor modules + * - Calls to `new` on the module object + * + * Note that this includes references to `self` in ancestor modules, but not in descendent modules. + * This is usually the desired behavior, particularly if this module was itself found using + * a call to `getADescendentModule()`. + */ + bindingset[this] + pragma[inline] + API::Node trackInstance() { result = API::Internal::getModuleInstance(this) } } /** @@ -1216,6 +1308,9 @@ class MethodNode extends CallableNode { /** Holds if this method is protected. */ predicate isProtected() { this.asCallableAstNode().isProtected() } + + /** Gets a `super` call in this method. */ + CallNode getASuperCall() { methodHasSuperCall(this, result) } } /** @@ -1291,6 +1386,11 @@ class ArrayLiteralNode extends LocalSourceNode, ExprNode { * Gets an element of the array. */ Node getAnElement() { result = this.(CallNode).getPositionalArgument(_) } + + /** + * Gets the `n`th element of the array. + */ + Node getElement(int n) { result = this.(CallNode).getPositionalArgument(n) } } /** @@ -1331,24 +1431,6 @@ class ConstRef extends LocalSourceNode { not exists(access.getScopeExpr()) } - /** - * Gets a module for which this constant is the reference to an ancestor module. - * - * For example, `M` is the ancestry target of `C` in the following examples: - * ```rb - * class M < C {} - * - * module M - * include C - * end - * - * module M - * prepend C - * end - * ``` - */ - private ModuleNode getAncestryTarget() { result.getAnAncestorExpr() = this } - /** * Gets the known target module. * @@ -1356,22 +1438,6 @@ class ConstRef extends LocalSourceNode { */ private Module getExactTarget() { result.getAnImmediateReference() = access } - /** - * Gets a scope in which a constant lookup may access the contents of the module referenced by this constant. - */ - cached - private TConstLookupScope getATargetScope() { - forceCachingInSameStage() and - result = MkAncestorLookup(this.getAncestryTarget().getAnImmediateDescendent*()) - or - access = any(ConstantAccess ac).getScopeExpr() and - result = MkQualifiedLookup(access) - or - result = MkNestedLookup(this.getAncestryTarget()) - or - result = MkExactLookup(access.(Namespace).getModule()) - } - /** * Gets the scope expression, or the immediately enclosing `Namespace` (skipping over singleton classes). * @@ -1433,7 +1499,7 @@ class ConstRef extends LocalSourceNode { pragma[inline] ConstRef getConstant(string name) { exists(TConstLookupScope scope | - pragma[only_bind_into](scope) = pragma[only_bind_out](this).getATargetScope() and + pragma[only_bind_into](scope) = getATargetScope(pragma[only_bind_out](this)) and result.accesses(pragma[only_bind_out](scope), name) ) } @@ -1455,7 +1521,14 @@ class ConstRef extends LocalSourceNode { * end * ``` */ - ModuleNode getADescendentModule() { MkAncestorLookup(result) = this.getATargetScope() } + pragma[inline] + ModuleNode getADescendentModule() { result = getADescendentModuleInline(this) } +} + +bindingset[ref] +pragma[inline_late] +private ModuleNode getADescendentModuleInline(ConstRef ref) { + MkAncestorLookup(result) = getATargetScope(ref) } /** diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/ModelsAsData.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/ModelsAsData.qll index 2e3fa21a45b..21bc5f69dcb 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/ModelsAsData.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/ModelsAsData.qll @@ -44,7 +44,7 @@ private class SummarizedCallableFromModel extends SummarizedCallable { override Call getACall() { exists(API::MethodAccessNode base | ModelOutput::resolvedSummaryBase(type, path, base) and - result = base.getCallNode().asExpr().getExpr() + result = base.asCall().asExpr().getExpr() ) } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsSpecific.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsSpecific.qll index 4c03522a9c5..ed7a331c452 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -99,9 +99,10 @@ API::Node getExtraNodeFromPath(string type, AccessPath path, int n) { // A row of form `any;Method[foo]` should match any method named `foo`. type = "any" and n = 1 and - exists(EntryPointFromAnyType entry | - methodMatchedByName(path, entry.getName()) and - result = entry.getANode() + exists(string methodName, DataFlow::CallNode call | + methodMatchedByName(path, methodName) and + call.getMethodName() = methodName and + result.(API::MethodAccessNode).asCall() = call ) } @@ -112,20 +113,10 @@ API::Node getExtraNodeFromType(string type) { constRef = getConstantFromConstPath(consts) | suffix = "!" and - ( - result.(API::Node::Internal).asSourceInternal() = constRef - or - result.(API::Node::Internal).asSourceInternal() = - constRef.getADescendentModule().getAnOwnModuleSelf() - ) + result = constRef.track() or suffix = "" and - ( - result.(API::Node::Internal).asSourceInternal() = constRef.getAMethodCall("new") - or - result.(API::Node::Internal).asSourceInternal() = - constRef.getADescendentModule().getAnInstanceSelf() - ) + result = constRef.track().getInstance() ) or type = "" and @@ -145,21 +136,6 @@ private predicate methodMatchedByName(AccessPath path, string methodName) { ) } -/** - * An API graph entry point corresponding to a method name such as `foo` in `;any;Method[foo]`. - * - * This ensures that the API graph rooted in that method call is materialized. - */ -private class EntryPointFromAnyType extends API::EntryPoint { - string name; - - EntryPointFromAnyType() { this = "AnyMethod[" + name + "]" and methodMatchedByName(_, name) } - - override DataFlow::CallNode getACall() { result.getMethodName() = name } - - string getName() { result = name } -} - /** * Gets a Ruby-specific API graph successor of `node` reachable by resolving `token`. */ @@ -175,9 +151,11 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) { result = node.getInstance() or token.getName() = "Parameter" and - result = - node.getASuccessor(API::Label::getLabelFromParameterPosition(FlowSummaryImplSpecific::parseArgBody(token - .getAnArgument()))) + exists(DataFlowDispatch::ArgumentPosition argPos, DataFlowDispatch::ParameterPosition paramPos | + argPos = FlowSummaryImplSpecific::parseParamBody(token.getAnArgument()) and + DataFlowDispatch::parameterMatch(paramPos, argPos) and + result = node.getParameterAtPosition(paramPos) + ) or exists(DataFlow::ContentSet contents | SummaryComponent::content(contents) = FlowSummaryImplSpecific::interpretComponentSpecific(token) and @@ -191,9 +169,11 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) { bindingset[token] API::Node getExtraSuccessorFromInvoke(InvokeNode node, AccessPathToken token) { token.getName() = "Argument" and - result = - node.getASuccessor(API::Label::getLabelFromArgumentPosition(FlowSummaryImplSpecific::parseParamBody(token - .getAnArgument()))) + exists(DataFlowDispatch::ArgumentPosition argPos, DataFlowDispatch::ParameterPosition paramPos | + paramPos = FlowSummaryImplSpecific::parseArgBody(token.getAnArgument()) and + DataFlowDispatch::parameterMatch(paramPos, argPos) and + result = node.getArgumentAtPosition(argPos) + ) } /** @@ -211,7 +191,7 @@ predicate invocationMatchesExtraCallSiteFilter(InvokeNode invoke, AccessPathToke /** An API graph node representing a method call. */ class InvokeNode extends API::MethodAccessNode { /** Gets the number of arguments to the call. */ - int getNumArgument() { result = this.getCallNode().getNumberOfArguments() } + int getNumArgument() { result = this.asCall().getNumberOfArguments() } } /** Gets the `InvokeNode` corresponding to a specific invocation of `node`. */ diff --git a/ruby/ql/lib/codeql/ruby/typetracking/ApiGraphShared.qll b/ruby/ql/lib/codeql/ruby/typetracking/ApiGraphShared.qll new file mode 100644 index 00000000000..e27384b1c7b --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/typetracking/ApiGraphShared.qll @@ -0,0 +1,329 @@ +/** + * Parts of API graphs that can be shared with other dynamic languages. + * + * Depends on TypeTrackerSpecific for the corresponding language. + */ + +private import codeql.Locations +private import codeql.ruby.typetracking.TypeTracker +private import TypeTrackerSpecific + +/** + * The signature to use when instantiating `ApiGraphShared`. + * + * The implementor should define a newtype with at least three branches as follows: + * ```ql + * newtype TApiNode = + * MkForwardNode(LocalSourceNode node, TypeTracker t) { isReachable(node, t) } or + * MkBackwardNode(LocalSourceNode node, TypeTracker t) { isReachable(node, t) } or + * MkSinkNode(Node node) { ... } or + * ... + * ``` + * + * The three branches should be exposed through `getForwardNode`, `getBackwardNode`, and `getSinkNode`, respectively. + */ +signature module ApiGraphSharedSig { + /** A node in the API graph. */ + class ApiNode { + /** Gets a string representation of this API node. */ + string toString(); + + /** Gets the location associated with this API node, if any. */ + Location getLocation(); + } + + /** + * Gets the forward node with the given type-tracking state. + * + * This node will have outgoing epsilon edges to its type-tracking successors. + */ + ApiNode getForwardNode(TypeTrackingNode node, TypeTracker t); + + /** + * Gets the backward node with the given type-tracking state. + * + * This node will have outgoing epsilon edges to its type-tracking predecessors. + */ + ApiNode getBackwardNode(TypeTrackingNode node, TypeTracker t); + + /** + * Gets the sink node corresponding to `node`. + * + * Since sinks are not generally `LocalSourceNode`s, such nodes are materialised separately in order for + * the API graph to include representatives for sinks. Note that there is no corresponding case for "source" + * nodes as these are represented as forward nodes with initial-state type-trackers. + * + * Sink nodes have outgoing epsilon edges to the backward nodes corresponding to their local sources. + */ + ApiNode getSinkNode(Node node); + + /** + * Holds if a language-specific epsilon edge `pred -> succ` should be generated. + */ + predicate specificEpsilonEdge(ApiNode pred, ApiNode succ); +} + +/** + * Parts of API graphs that can be shared between language implementations. + */ +module ApiGraphShared { + private import S + + /** Gets a local source of `node`. */ + bindingset[node] + pragma[inline_late] + TypeTrackingNode getALocalSourceStrict(Node node) { result = node.getALocalSource() } + + cached + private module Cached { + /** + * Holds if there is an epsilon edge `pred -> succ`. + * + * That relation is reflexive, so `fastTC` produces the equivalent of a reflexive, transitive closure. + */ + pragma[noopt] + cached + predicate epsilonEdge(ApiNode pred, ApiNode succ) { + // forward + exists( + StepSummary summary, TypeTrackingNode predNode, TypeTracker predState, + TypeTrackingNode succNode, TypeTracker succState + | + StepSummary::stepCall(predNode, succNode, summary) + or + StepSummary::stepNoCall(predNode, succNode, summary) + | + pred = getForwardNode(predNode, predState) and + succState = StepSummary::append(predState, summary) and + succ = getForwardNode(succNode, succState) + or + succ = getBackwardNode(predNode, predState) and // swap order for backward flow + succState = StepSummary::append(predState, summary) and + pred = getBackwardNode(succNode, succState) // swap order for backward flow + ) + or + exists(Node sink, TypeTrackingNode localSource | + pred = getSinkNode(sink) and + localSource = getALocalSourceStrict(sink) and + succ = getBackwardStartNode(localSource) + ) + or + specificEpsilonEdge(pred, succ) + or + succ instanceof ApiNode and + succ = pred + } + + /** + * Holds if `pred` can reach `succ` by zero or more epsilon edges. + */ + cached + predicate epsilonStar(ApiNode pred, ApiNode succ) = fastTC(epsilonEdge/2)(pred, succ) + + /** Gets the API node to use when starting forward flow from `source` */ + cached + ApiNode forwardStartNode(TypeTrackingNode source) { + result = getForwardNode(source, TypeTracker::end(false)) + } + + /** Gets the API node to use when starting backward flow from `sink` */ + cached + ApiNode backwardStartNode(TypeTrackingNode sink) { + // There is backward flow A->B iff there is forward flow B->A. + // The starting point of backward flow corresponds to the end of a forward flow, and vice versa. + result = getBackwardNode(sink, TypeTracker::end(_)) + } + + /** Gets `node` as a data flow source. */ + cached + TypeTrackingNode asSourceCached(ApiNode node) { node = forwardEndNode(result) } + + /** Gets `node` as a data flow sink. */ + cached + Node asSinkCached(ApiNode node) { node = getSinkNode(result) } + } + + private import Cached + + /** Gets an API node corresponding to the end of forward-tracking to `localSource`. */ + pragma[nomagic] + private ApiNode forwardEndNode(TypeTrackingNode localSource) { + result = getForwardNode(localSource, TypeTracker::end(_)) + } + + /** Gets an API node corresponding to the end of backtracking to `localSource`. */ + pragma[nomagic] + private ApiNode backwardEndNode(TypeTrackingNode localSource) { + result = getBackwardNode(localSource, TypeTracker::end(false)) + } + + /** Gets a node reachable from `node` by zero or more epsilon edges, including `node` itself. */ + bindingset[node] + pragma[inline_late] + ApiNode getAnEpsilonSuccessorInline(ApiNode node) { epsilonStar(node, result) } + + /** Gets `node` as a data flow sink. */ + bindingset[node] + pragma[inline_late] + Node asSinkInline(ApiNode node) { result = asSinkCached(node) } + + /** Gets `node` as a data flow source. */ + bindingset[node] + pragma[inline_late] + TypeTrackingNode asSourceInline(ApiNode node) { result = asSourceCached(node) } + + /** Gets a value reachable from `source`. */ + bindingset[source] + pragma[inline_late] + Node getAValueReachableFromSourceInline(ApiNode source) { + exists(TypeTrackingNode src | + src = asSourceInline(getAnEpsilonSuccessorInline(source)) and + src.flowsTo(pragma[only_bind_into](result)) + ) + } + + /** Gets a value that can reach `sink`. */ + bindingset[sink] + pragma[inline_late] + Node getAValueReachingSinkInline(ApiNode sink) { + result = asSinkInline(getAnEpsilonSuccessorInline(sink)) + } + + /** + * Gets the starting point for forward-tracking at `node`. + * + * Should be used to obtain the successor of an edge when constructing labelled edges. + */ + bindingset[node] + pragma[inline_late] + ApiNode getForwardStartNode(Node node) { result = forwardStartNode(node) } + + /** + * Gets the starting point of backtracking from `node`. + * + * Should be used to obtain the successor of an edge when constructing labelled edges. + */ + bindingset[node] + pragma[inline_late] + ApiNode getBackwardStartNode(Node node) { result = backwardStartNode(node) } + + /** + * Gets a possible ending point of forward-tracking at `node`. + * + * Should be used to obtain the predecessor of an edge when constructing labelled edges. + * + * This is not backed by a `cached` predicate, and should only be used for materialising `cached` + * predicates in the API graph implementation - it should not be called in later stages. + */ + bindingset[node] + pragma[inline_late] + ApiNode getForwardEndNode(Node node) { result = forwardEndNode(node) } + + /** + * Gets a possible ending point backtracking to `node`. + * + * Should be used to obtain the predecessor of an edge when constructing labelled edges. + * + * This is not backed by a `cached` predicate, and should only be used for materialising `cached` + * predicates in the API graph implementation - it should not be called in later stages. + */ + bindingset[node] + pragma[inline_late] + ApiNode getBackwardEndNode(Node node) { result = backwardEndNode(node) } + + /** + * Gets a possible eding point of forward or backward tracking at `node`. + * + * Should be used to obtain the predecessor of an edge generated from store or load edges. + */ + bindingset[node] + pragma[inline_late] + ApiNode getForwardOrBackwardEndNode(Node node) { + result = getForwardEndNode(node) or result = getBackwardEndNode(node) + } + + /** Gets an API node for tracking forward starting at `node`. This is the implementation of `DataFlow::LocalSourceNode.track()` */ + bindingset[node] + pragma[inline_late] + ApiNode getNodeForForwardTracking(Node node) { result = forwardStartNode(node) } + + /** Gets an API node for backtracking starting at `node`. The implementation of `DataFlow::Node.backtrack()`. */ + bindingset[node] + pragma[inline_late] + ApiNode getNodeForBacktracking(Node node) { + result = getBackwardStartNode(getALocalSourceStrict(node)) + } + + /** Parts of the shared module to be re-exported by the user-facing `API` module. */ + module Public { + /** + * The signature to use when instantiating the `ExplainFlow` module. + */ + signature module ExplainFlowSig { + /** Holds if `node` should be a source. */ + predicate isSource(ApiNode node); + + /** Holds if `node` should be a sink. */ + default predicate isSink(ApiNode node) { any() } + + /** Holds if `node` should be skipped in the generated paths. */ + default predicate isHidden(ApiNode node) { none() } + } + + /** + * Module to help debug and visualize the data flows underlying API graphs. + * + * This module exports the query predicates for a path-problem query, and should be imported + * into the top-level of such a query. + * + * The module argument should specify source and sink API nodes, and the resulting query + * will show paths of epsilon edges that go from a source to a sink. Only epsilon edges are visualized. + * + * To condense the output a bit, paths in which the source and sink are the same node are omitted. + */ + module ExplainFlow { + private import T + + private ApiNode relevantNode() { + isSink(result) and + result = getAnEpsilonSuccessorInline(any(ApiNode node | isSource(node))) + or + epsilonEdge(result, relevantNode()) + } + + /** Holds if `node` is part of the graph to visualize. */ + query predicate nodes(ApiNode node) { node = relevantNode() and not isHidden(node) } + + private predicate edgeToHiddenNode(ApiNode pred, ApiNode succ) { + epsilonEdge(pred, succ) and + isHidden(succ) and + pred = relevantNode() and + succ = relevantNode() + } + + /** Holds if `pred -> succ` is an edge in the graph to visualize. */ + query predicate edges(ApiNode pred, ApiNode succ) { + nodes(pred) and + nodes(succ) and + exists(ApiNode mid | + edgeToHiddenNode*(pred, mid) and + epsilonEdge(mid, succ) + ) + } + + /** Holds for each source/sink pair to visualize in the graph. */ + query predicate problems( + ApiNode location, ApiNode sourceNode, ApiNode sinkNode, string message + ) { + nodes(sourceNode) and + nodes(sinkNode) and + isSource(sourceNode) and + isSink(sinkNode) and + sinkNode = getAnEpsilonSuccessorInline(sourceNode) and + sourceNode != sinkNode and + location = sinkNode and + message = "Node flows here" + } + } + } +} diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll index 25521f5f1a5..74c67b5be78 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll @@ -55,10 +55,9 @@ private module Cached { ) } - pragma[nomagic] - private TypeTracker noContentTypeTracker(boolean hasCall) { - result = MkTypeTracker(hasCall, noContent()) - } + /** Gets a type tracker with no content and the call bit set to the given value. */ + cached + TypeTracker noContentTypeTracker(boolean hasCall) { result = MkTypeTracker(hasCall, noContent()) } /** Gets the summary resulting from appending `step` to type-tracking summary `tt`. */ cached @@ -340,6 +339,8 @@ class StepSummary extends TStepSummary { /** Provides predicates for updating step summaries (`StepSummary`s). */ module StepSummary { + predicate append = Cached::append/2; + /** * Gets the summary that corresponds to having taken a forwards * inter-procedural step from `nodeFrom` to `nodeTo`. @@ -400,6 +401,35 @@ module StepSummary { } deprecated predicate localSourceStoreStep = flowsToStoreStep/3; + + /** Gets the step summary for a level step. */ + StepSummary levelStep() { result = LevelStep() } + + /** Gets the step summary for a call step. */ + StepSummary callStep() { result = CallStep() } + + /** Gets the step summary for a return step. */ + StepSummary returnStep() { result = ReturnStep() } + + /** Gets the step summary for storing into `content`. */ + StepSummary storeStep(TypeTrackerContent content) { result = StoreStep(content) } + + /** Gets the step summary for loading from `content`. */ + StepSummary loadStep(TypeTrackerContent content) { result = LoadStep(content) } + + /** Gets the step summary for loading from `load` and then storing into `store`. */ + StepSummary loadStoreStep(TypeTrackerContent load, TypeTrackerContent store) { + result = LoadStoreStep(load, store) + } + + /** Gets the step summary for a step that only permits contents matched by `filter`. */ + StepSummary withContent(ContentFilter filter) { result = WithContent(filter) } + + /** Gets the step summary for a step that blocks contents matched by `filter`. */ + StepSummary withoutContent(ContentFilter filter) { result = WithoutContent(filter) } + + /** Gets the step summary for a jump step. */ + StepSummary jumpStep() { result = JumpStep() } } /** @@ -545,6 +575,13 @@ module TypeTracker { * Gets a valid end point of type tracking. */ TypeTracker end() { result.end() } + + /** + * INTERNAL USE ONLY. + * + * Gets a valid end point of type tracking with the call bit set to the given value. + */ + predicate end = Cached::noContentTypeTracker/1; } pragma[nomagic] diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/ApiGraphs.expected b/ruby/ql/test/library-tests/dataflow/api-graphs/ApiGraphs.expected index 43b6490b052..5677b16fedb 100644 --- a/ruby/ql/test/library-tests/dataflow/api-graphs/ApiGraphs.expected +++ b/ruby/ql/test/library-tests/dataflow/api-graphs/ApiGraphs.expected @@ -1,8 +1,8 @@ classMethodCalls -| test1.rb:58:1:58:8 | Use getMember("M1").getMember("C1").getMethod("m").getReturn() | -| test1.rb:59:1:59:8 | Use getMember("M2").getMember("C3").getMethod("m").getReturn() | +| test1.rb:58:1:58:8 | ForwardNode(call to m) | +| test1.rb:59:1:59:8 | ForwardNode(call to m) | instanceMethodCalls -| test1.rb:61:1:61:12 | Use getMember("M1").getMember("C1").getMethod("new").getReturn().getMethod("m").getReturn() | -| test1.rb:62:1:62:12 | Use getMember("M2").getMember("C3").getMethod("new").getReturn().getMethod("m").getReturn() | +| test1.rb:61:1:61:12 | ForwardNode(call to m) | +| test1.rb:62:1:62:12 | ForwardNode(call to m) | flowThroughArray | test1.rb:73:1:73:10 | call to m | diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/use.expected b/ruby/ql/test/library-tests/dataflow/api-graphs/VerifyApiGraphExpectations.expected similarity index 100% rename from ruby/ql/test/library-tests/dataflow/api-graphs/use.expected rename to ruby/ql/test/library-tests/dataflow/api-graphs/VerifyApiGraphExpectations.expected diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/VerifyApiGraphExpectations.ql b/ruby/ql/test/library-tests/dataflow/api-graphs/VerifyApiGraphExpectations.ql new file mode 100644 index 00000000000..93b5aaf745e --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/api-graphs/VerifyApiGraphExpectations.ql @@ -0,0 +1,77 @@ +import ruby +import codeql.ruby.ast.internal.TreeSitter +import codeql.ruby.dataflow.internal.AccessPathSyntax +import codeql.ruby.frameworks.data.internal.ApiGraphModels +import codeql.ruby.ApiGraphs +import TestUtilities.InlineExpectationsTest + +class AccessPathFromExpectation extends AccessPath::Range { + AccessPathFromExpectation() { hasExpectationWithValue(_, this) } +} + +API::Node evaluatePath(AccessPath path, int n) { + path instanceof AccessPathFromExpectation and + n = 1 and + exists(AccessPathToken token | token = path.getToken(0) | + token.getName() = "Member" and + result = API::getTopLevelMember(token.getAnArgument()) + or + token.getName() = "Method" and + result = API::getTopLevelCall(token.getAnArgument()) + or + token.getName() = "EntryPoint" and + result = token.getAnArgument().(API::EntryPoint).getANode() + ) + or + result = getSuccessorFromNode(evaluatePath(path, n - 1), path.getToken(n - 1)) + or + result = getSuccessorFromInvoke(evaluatePath(path, n - 1), path.getToken(n - 1)) + or + // TODO this is a workaround, support parsing of Method['[]'] instead + path.getToken(n - 1).getName() = "MethodBracket" and + result = evaluatePath(path, n - 1).getMethod("[]") +} + +API::Node evaluatePath(AccessPath path) { result = evaluatePath(path, path.getNumToken()) } + +module ApiUseTest implements TestSig { + string getARelevantTag() { result = ["source", "sink", "call", "reachableFromSource"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + // All results are considered optional + none() + } + + predicate hasOptionalResult(Location location, string element, string tag, string value) { + exists(API::Node apiNode, DataFlow::Node dataflowNode | + apiNode = evaluatePath(value) and + ( + tag = "source" and dataflowNode = apiNode.asSource() + or + tag = "reachableFromSource" and dataflowNode = apiNode.getAValueReachableFromSource() + or + tag = "sink" and dataflowNode = apiNode.asSink() + or + tag = "call" and dataflowNode = apiNode.asCall() + ) and + location = dataflowNode.getLocation() and + element = dataflowNode.toString() + ) + } +} + +import MakeTest + +class CustomEntryPointCall extends API::EntryPoint { + CustomEntryPointCall() { this = "CustomEntryPointCall" } + + override DataFlow::CallNode getACall() { result.getMethodName() = "customEntryPointCall" } +} + +class CustomEntryPointUse extends API::EntryPoint { + CustomEntryPointUse() { this = "CustomEntryPointUse" } + + override DataFlow::LocalSourceNode getASource() { + result.(DataFlow::CallNode).getMethodName() = "customEntryPointUse" + } +} diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/callbacks.rb b/ruby/ql/test/library-tests/dataflow/api-graphs/callbacks.rb index 34c4d17d212..35cf4471b48 100644 --- a/ruby/ql/test/library-tests/dataflow/api-graphs/callbacks.rb +++ b/ruby/ql/test/library-tests/dataflow/api-graphs/callbacks.rb @@ -1,39 +1,39 @@ -Something.foo.withCallback do |a, b| #$ use=getMember("Something").getMethod("foo").getReturn() - a.something #$ use=getMember("Something").getMethod("foo").getReturn().getMethod("withCallback").getBlock().getParameter(0).getMethod("something").getReturn() - b.somethingElse #$ use=getMember("Something").getMethod("foo").getReturn().getMethod("withCallback").getBlock().getParameter(1).getMethod("somethingElse").getReturn() -end #$ use=getMember("Something").getMethod("foo").getReturn().getMethod("withCallback").getReturn() +Something.foo.withCallback do |a, b| #$ source=Member[Something].Method[foo].ReturnValue + a.something #$ source=Member[Something].Method[foo].ReturnValue.Method[withCallback].Argument[block].Argument[0].Method[something].ReturnValue + b.somethingElse #$ source=Member[Something].Method[foo].ReturnValue.Method[withCallback].Argument[block].Argument[1].Method[somethingElse].ReturnValue +end #$ source=Member[Something].Method[foo].ReturnValue.Method[withCallback].ReturnValue -Something.withNamedArg do |a:, b: nil| #$ use=getMember("Something") - a.something #$ use=getMember("Something").getMethod("withNamedArg").getBlock().getKeywordParameter("a").getMethod("something").getReturn() - b.somethingElse #$ use=getMember("Something").getMethod("withNamedArg").getBlock().getKeywordParameter("b").getMethod("somethingElse").getReturn() -end #$ use=getMember("Something").getMethod("withNamedArg").getReturn() +Something.withNamedArg do |a:, b: nil| #$ source=Member[Something] + a.something #$ source=Member[Something].Method[withNamedArg].Argument[block].Parameter[a:].Method[something].ReturnValue + b.somethingElse #$ source=Member[Something].Method[withNamedArg].Argument[block].Parameter[b:].Method[somethingElse].ReturnValue +end #$ source=Member[Something].Method[withNamedArg].ReturnValue -Something.withLambda ->(a, b) { #$ use=getMember("Something") - a.something #$ use=getMember("Something").getMethod("withLambda").getParameter(0).getParameter(0).getMethod("something").getReturn() - b.something #$ use=getMember("Something").getMethod("withLambda").getParameter(0).getParameter(1).getMethod("something").getReturn() -} #$ use=getMember("Something").getMethod("withLambda").getReturn() +Something.withLambda ->(a, b) { #$ source=Member[Something] + a.something #$ source=Member[Something].Method[withLambda].Argument[0].Parameter[0].Method[something].ReturnValue + b.something #$ source=Member[Something].Method[withLambda].Argument[0].Parameter[1].Method[something].ReturnValue +} #$ source=Member[Something].Method[withLambda].ReturnValue -Something.namedCallback( #$ use=getMember("Something") +Something.namedCallback( #$ source=Member[Something] onEvent: ->(a, b) { - a.something #$ use=getMember("Something").getMethod("namedCallback").getKeywordParameter("onEvent").getParameter(0).getMethod("something").getReturn() - b.something #$ use=getMember("Something").getMethod("namedCallback").getKeywordParameter("onEvent").getParameter(1).getMethod("something").getReturn() + a.something #$ source=Member[Something].Method[namedCallback].Argument[onEvent:].Parameter[0].Method[something].ReturnValue + b.something #$ source=Member[Something].Method[namedCallback].Argument[onEvent:].Parameter[1].Method[something].ReturnValue } -) #$ use=getMember("Something").getMethod("namedCallback").getReturn() +) #$ source=Member[Something].Method[namedCallback].ReturnValue -Something.nestedCall1 do |a| #$ use=getMember("Something") - a.nestedCall2 do |b:| #$ use=getMember("Something").getMethod("nestedCall1").getBlock().getParameter(0) - b.something #$ use=getMember("Something").getMethod("nestedCall1").getBlock().getParameter(0).getMethod("nestedCall2").getBlock().getKeywordParameter("b").getMethod("something").getReturn() - end #$ use=getMember("Something").getMethod("nestedCall1").getBlock().getParameter(0).getMethod("nestedCall2").getReturn() -end #$ use=getMember("Something").getMethod("nestedCall1").getReturn() +Something.nestedCall1 do |a| #$ source=Member[Something] + a.nestedCall2 do |b:| #$ reachableFromSource=Member[Something].Method[nestedCall1].Argument[block].Parameter[0] + b.something #$ source=Member[Something].Method[nestedCall1].Argument[block].Parameter[0].Method[nestedCall2].Argument[block].Parameter[b:].Method[something].ReturnValue + end #$ source=Member[Something].Method[nestedCall1].Argument[block].Parameter[0].Method[nestedCall2].ReturnValue +end #$ source=Member[Something].Method[nestedCall1].ReturnValue def getCallback() ->(x) { - x.something #$ use=getMember("Something").getMethod("indirectCallback").getParameter(0).getParameter(0).getMethod("something").getReturn() + x.something #$ source=Member[Something].Method[indirectCallback].Argument[0].Parameter[0].Method[something].ReturnValue } end -Something.indirectCallback(getCallback()) #$ use=getMember("Something").getMethod("indirectCallback").getReturn() +Something.indirectCallback(getCallback()) #$ source=Member[Something].Method[indirectCallback].ReturnValue -Something.withMixed do |a, *args, b| #$ use=getMember("Something") - a.something #$ use=getMember("Something").getMethod("withMixed").getBlock().getParameter(0).getMethod("something").getReturn() +Something.withMixed do |a, *args, b| #$ source=Member[Something] + a.something #$ source=Member[Something].Method[withMixed].Argument[block].Parameter[0].Method[something].ReturnValue # b.something # not currently handled correctly -end #$ use=getMember("Something").getMethod("withMixed").getReturn() +end #$ source=Member[Something].Method[withMixed].ReturnValue diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/chained-access.rb b/ruby/ql/test/library-tests/dataflow/api-graphs/chained-access.rb new file mode 100644 index 00000000000..b0e4f07e701 --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/api-graphs/chained-access.rb @@ -0,0 +1,31 @@ +def chained_access1 + Something.foo [[[ + 'sink' # $ sink=Member[Something].Method[foo].Argument[0].Element[0].Element[0].Element[0] + ]]] +end + +def chained_access2 + array = [] + array[0] = [[ + 'sink' # $ sink=Member[Something].Method[foo].Argument[0].Element[0].Element[0].Element[0] + ]] + Something.foo array +end + +def chained_access3 + array = [[]] + array[0][0] = [ + 'sink' # $ sink=Member[Something].Method[foo].Argument[0].Element[0].Element[0].Element[0] + ] + Something.foo array +end + +def chained_access4 + Something.foo { + :one => { + :two => { + :three => 'sink' # $ sink=Member[Something].Method[foo].Argument[0].Element[:one].Element[:two].Element[:three] + } + } + } +end diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/method-callbacks.rb b/ruby/ql/test/library-tests/dataflow/api-graphs/method-callbacks.rb new file mode 100644 index 00000000000..63a4b4c3dce --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/api-graphs/method-callbacks.rb @@ -0,0 +1,64 @@ +class BaseClass + def inheritedInstanceMethod + yield "taint" # $ sink=Member[Something].Method[foo].Argument[block].ReturnValue.Method[inheritedInstanceMethod].Parameter[block].Argument[0] + end + + def self.inheritedSingletonMethod + yield "taint" # $ sink=Member[Something].Method[bar].Argument[block].ReturnValue.Method[inheritedSingletonMethod].Parameter[block].Argument[0] + end +end + +class ClassWithCallbacks < BaseClass + def instanceMethod + yield "taint" # $ sink=Member[Something].Method[foo].Argument[block].ReturnValue.Method[instanceMethod].Parameter[block].Argument[0] + end + + def self.singletonMethod + yield "bar" # $ sink=Member[Something].Method[bar].Argument[block].ReturnValue.Method[singletonMethod].Parameter[block].Argument[0] + end + + def escapeSelf + Something.baz { self } + end + + def self.escapeSingletonSelf + Something.baz { self } + end + + def self.foo x + x # $ reachableFromSource=Member[BaseClass].Method[foo].Parameter[0] + x # $ reachableFromSource=Member[ClassWithCallbacks].Method[foo].Parameter[0] + x # $ reachableFromSource=Member[Subclass].Method[foo].Parameter[0] + end + + def bar x + x # $ reachableFromSource=Member[BaseClass].Instance.Method[bar].Parameter[0] + x # $ reachableFromSource=Member[ClassWithCallbacks].Instance.Method[bar].Parameter[0] + x # $ reachableFromSource=Member[Subclass].Instance.Method[bar].Parameter[0] + end +end + +class Subclass < ClassWithCallbacks + def instanceMethodInSubclass + yield "bar" # $ sink=Member[Something].Method[baz].Argument[block].ReturnValue.Method[instanceMethodInSubclass].Parameter[block].Argument[0] + end + + def self.singletonMethodInSubclass + yield "bar" # $ sink=Member[Something].Method[baz].Argument[block].ReturnValue.Method[singletonMethodInSubclass].Parameter[block].Argument[0] + end +end + +Something.foo { ClassWithCallbacks.new } +Something.bar { ClassWithCallbacks } + +class ClassWithCallMethod + def call x + x # $ reachableFromSource=Method[topLevelMethod].Argument[0].Parameter[0] + "bar" # $ sink=Method[topLevelMethod].Argument[0].ReturnValue + end +end + +topLevelMethod ClassWithCallMethod.new + +blah = topLevelMethod +blah # $ reachableFromSource=Method[topLevelMethod].ReturnValue diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/test1.rb b/ruby/ql/test/library-tests/dataflow/api-graphs/test1.rb index 86b8bce9587..3af793dd4f7 100644 --- a/ruby/ql/test/library-tests/dataflow/api-graphs/test1.rb +++ b/ruby/ql/test/library-tests/dataflow/api-graphs/test1.rb @@ -1,34 +1,34 @@ -MyModule #$ use=getMember("MyModule") -print MyModule.foo #$ use=getMember("MyModule").getMethod("foo").getReturn() -Kernel.print(e) #$ use=getMember("Kernel").getMethod("print").getReturn() def=getMember("Kernel").getMethod("print").getParameter(0) -Object::Kernel #$ use=getMember("Kernel") -Object::Kernel.print(e) #$ use=getMember("Kernel").getMethod("print").getReturn() +MyModule #$ source=Member[MyModule] +print MyModule.foo #$ source=Member[MyModule].Method[foo].ReturnValue +Kernel.print(e) #$ source=Member[Kernel].Method[print].ReturnValue sink=Member[Kernel].Method[print].Argument[0] +Object::Kernel #$ source=Member[Kernel] +Object::Kernel.print(e) #$ source=Member[Kernel].Method[print].ReturnValue begin - print MyModule.bar #$ use=getMember("MyModule").getMethod("bar").getReturn() - raise AttributeError #$ use=getMember("AttributeError") -rescue AttributeError => e #$ use=getMember("AttributeError") - Kernel.print(e) #$ use=getMember("Kernel").getMethod("print").getReturn() + print MyModule.bar #$ source=Member[MyModule].Method[bar].ReturnValue + raise AttributeError #$ source=Member[AttributeError] +rescue AttributeError => e #$ source=Member[AttributeError] + Kernel.print(e) #$ source=Member[Kernel].Method[print].ReturnValue end -Unknown.new.run #$ use=getMember("Unknown").getMethod("new").getReturn().getMethod("run").getReturn() -Foo::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz") +Unknown.new.run #$ source=Member[Unknown].Method[new].ReturnValue.Method[run].ReturnValue +Foo::Bar::Baz #$ source=Member[Foo].Member[Bar].Member[Baz] -Const = [1, 2, 3] #$ use=getMember("Array").getMethod("[]").getReturn() -Const.each do |c| #$ use=getMember("Const") - puts c #$ use=getMember("Const").getMethod("each").getBlock().getParameter(0) use=getMember("Const").getContent(element) -end #$ use=getMember("Const").getMethod("each").getReturn() def=getMember("Const").getMethod("each").getBlock() +Const = [1, 2, 3] #$ source=Member[Array].MethodBracket.ReturnValue +Const.each do |c| #$ source=Member[Const] + puts c #$ reachableFromSource=Member[Const].Method[each].Argument[block].Parameter[0] reachableFromSource=Member[Const].Element[any] +end #$ source=Member[Const].Method[each].ReturnValue sink=Member[Const].Method[each].Argument[block] -foo = Foo #$ use=getMember("Foo") -foo::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz") +foo = Foo #$ source=Member[Foo] +foo::Bar::Baz #$ source=Member[Foo].Member[Bar].Member[Baz] -FooAlias = Foo #$ use=getMember("Foo") -FooAlias::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz") +FooAlias = Foo #$ source=Member[Foo] +FooAlias::Bar::Baz #$ source=Member[Foo].Member[Bar].Member[Baz] source=Member[FooAlias].Member[Bar].Member[Baz] module Outer module Inner end end -Outer::Inner.foo #$ use=getMember("Outer").getMember("Inner").getMethod("foo").getReturn() +Outer::Inner.foo #$ source=Member[Outer].Member[Inner].Method[foo].ReturnValue module M1 class C1 @@ -40,36 +40,36 @@ module M1 end end -class C2 < M1::C1 #$ use=getMember("M1").getMember("C1") +class C2 < M1::C1 #$ source=Member[M1].Member[C1] end module M2 - class C3 < M1::C1 #$ use=getMember("M1").getMember("C1") + class C3 < M1::C1 #$ source=Member[M1].Member[C1] end - class C4 < C2 #$ use=getMember("C2") + class C4 < C2 #$ source=Member[C2] end end -C2 #$ use=getMember("C2") use=getMember("M1").getMember("C1").getASubclass() -M2::C3 #$ use=getMember("M2").getMember("C3") use=getMember("M1").getMember("C1").getASubclass() -M2::C4 #$ use=getMember("M2").getMember("C4") use=getMember("C2").getASubclass() use=getMember("M1").getMember("C1").getASubclass().getASubclass() +C2 #$ source=Member[C2] reachableFromSource=Member[M1].Member[C1] +M2::C3 #$ source=Member[M2].Member[C3] reachableFromSource=Member[M1].Member[C1] +M2::C4 #$ source=Member[M2].Member[C4] reachableFromSource=Member[C2] reachableFromSource=Member[M1].Member[C1] -M1::C1.m #$ use=getMember("M1").getMember("C1").getMethod("m").getReturn() -M2::C3.m #$ use=getMember("M2").getMember("C3").getMethod("m").getReturn() use=getMember("M1").getMember("C1").getASubclass().getMethod("m").getReturn() +M1::C1.m #$ source=Member[M1].Member[C1].Method[m].ReturnValue +M2::C3.m #$ source=Member[M2].Member[C3].Method[m].ReturnValue source=Member[M1].Member[C1].Method[m].ReturnValue -M1::C1.new.m #$ use=getMember("M1").getMember("C1").getMethod("new").getReturn().getMethod("m").getReturn() -M2::C3.new.m #$ use=getMember("M2").getMember("C3").getMethod("new").getReturn().getMethod("m").getReturn() +M1::C1.new.m #$ source=Member[M1].Member[C1].Method[new].ReturnValue.Method[m].ReturnValue +M2::C3.new.m #$ source=Member[M2].Member[C3].Method[new].ReturnValue.Method[m].ReturnValue -Foo.foo(a,b:c) #$ use=getMember("Foo").getMethod("foo").getReturn() def=getMember("Foo").getMethod("foo").getParameter(0) def=getMember("Foo").getMethod("foo").getKeywordParameter("b") +Foo.foo(a,b:c) #$ source=Member[Foo].Method[foo].ReturnValue sink=Member[Foo].Method[foo].Argument[0] sink=Member[Foo].Method[foo].Argument[b:] def userDefinedFunction(x, y) x.noApiGraph(y) - x.customEntryPointCall(y) #$ call=entryPoint("CustomEntryPointCall") use=entryPoint("CustomEntryPointCall").getReturn() rhs=entryPoint("CustomEntryPointCall").getParameter(0) - x.customEntryPointUse(y) #$ use=entryPoint("CustomEntryPointUse") + x.customEntryPointCall(y) #$ call=EntryPoint[CustomEntryPointCall] source=EntryPoint[CustomEntryPointCall].ReturnValue sink=EntryPoint[CustomEntryPointCall].Parameter[0] + x.customEntryPointUse(y) #$ source=EntryPoint[CustomEntryPointUse] end -array = [A::B::C] #$ use=getMember("Array").getMethod("[]").getReturn() -array[0].m #$ use=getMember("A").getMember("B").getMember("C").getMethod("m").getReturn() +array = [A::B::C] #$ source=Member[Array].MethodBracket.ReturnValue +array[0].m #$ source=Member[A].Member[B].Member[C].Method[m].ReturnValue source=Member[Array].MethodBracket.ReturnValue.Element[0].Method[m].ReturnValue -A::B::C[0] #$ use=getMember("A").getMember("B").getMember("C").getContent(element_0) +A::B::C[0] #$ source=Member[A].Member[B].Member[C].Element[0] diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/use.ql b/ruby/ql/test/library-tests/dataflow/api-graphs/use.ql deleted file mode 100644 index a0c11640ce0..00000000000 --- a/ruby/ql/test/library-tests/dataflow/api-graphs/use.ql +++ /dev/null @@ -1,88 +0,0 @@ -import codeql.ruby.AST -import codeql.ruby.DataFlow -import TestUtilities.InlineExpectationsTest -import codeql.ruby.ApiGraphs - -class CustomEntryPointCall extends API::EntryPoint { - CustomEntryPointCall() { this = "CustomEntryPointCall" } - - override DataFlow::CallNode getACall() { result.getMethodName() = "customEntryPointCall" } -} - -class CustomEntryPointUse extends API::EntryPoint { - CustomEntryPointUse() { this = "CustomEntryPointUse" } - - override DataFlow::LocalSourceNode getASource() { - result.(DataFlow::CallNode).getMethodName() = "customEntryPointUse" - } -} - -module ApiUseTest implements TestSig { - string getARelevantTag() { result = ["use", "def", "call"] } - - private predicate relevantNode(API::Node a, DataFlow::Node n, Location l, string tag) { - l = n.getLocation() and - ( - tag = "use" and - n = a.getAValueReachableFromSource() - or - tag = "def" and - n = a.asSink() - or - tag = "call" and - n = a.(API::MethodAccessNode).getCallNode() - ) - } - - predicate hasActualResult(Location location, string element, string tag, string value) { - tag = "use" and // def tags are always optional - exists(DataFlow::Node n | relevantNode(_, n, location, tag) | - // Only report the longest path on this line: - value = - max(API::Node a2, Location l2, DataFlow::Node n2 | - relevantNode(a2, n2, l2, tag) and - l2.getFile() = location.getFile() and - l2.getEndLine() = location.getEndLine() - | - a2.getPath() - order by - size(n2.asExpr().getExpr()), a2.getPath().length() desc, a2.getPath() desc - ) and - element = n.toString() - ) - } - - // We also permit optional annotations for any other path on the line. - // This is used to test subclass paths, which typically have a shorter canonical path. - predicate hasOptionalResult(Location location, string element, string tag, string value) { - exists(API::Node a, DataFlow::Node n | relevantNode(a, n, location, tag) | - element = n.toString() and - value = getAPath(a, _) - ) - } -} - -import MakeTest - -private int size(AstNode n) { not n instanceof StmtSequence and result = count(n.getAChild*()) } - -/** - * Gets a path of the given `length` from the root to the given node. - * This is a copy of `API::getAPath()` without the restriction on path length, - * which would otherwise rule out paths involving `getASubclass()`. - */ -string getAPath(API::Node node, int length) { - node instanceof API::Root and - length = 0 and - result = "" - or - exists(API::Node pred, API::Label::ApiLabel lbl, string predpath | - pred.getASuccessor(lbl) = node and - predpath = getAPath(pred, length - 1) and - exists(string dot | if length = 1 then dot = "" else dot = "." | - result = predpath + dot + lbl and - // avoid producing strings longer than 1MB - result.length() < 1000 * 1000 - ) - ) -} diff --git a/shared/util/codeql/util/test/InlineExpectationsTest.qll b/shared/util/codeql/util/test/InlineExpectationsTest.qll index 7d3806cb4b5..8dc39af47ce 100644 --- a/shared/util/codeql/util/test/InlineExpectationsTest.qll +++ b/shared/util/codeql/util/test/InlineExpectationsTest.qll @@ -444,6 +444,19 @@ module Make { class FalseNegativeExpectation = LegacyTest::FalseNegativeTestExpectation; class InvalidExpectation = LegacyTest::InvalidTestExpectation; + + /** + * Holds if the expectation `tag=value` is found in one or more expectation comments. + * + * This can be used when writing tests where the set of possible values must be known in advance, + * for example, when testing a predicate for which `value` is part of the binding set. + */ + predicate hasExpectationWithValue(string tag, string value) { + exists(string tags | + getAnExpectation(_, _, _, tags, value) and + tag = tags.splitAt(",") + ) + } } /** From 5b05e72d27033005e49efcfd2a7db5be611aa084 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:02:39 +0200 Subject: [PATCH 173/364] Ruby: switch to local dataflow when dealing with Kernel/IO --- ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll | 3 ++- ruby/ql/lib/codeql/ruby/security/KernelOpenQuery.qll | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll b/ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll index b445521adb8..ad87ee37ecd 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll @@ -19,7 +19,8 @@ module Kernel { */ class KernelMethodCall extends DataFlow::CallNode { KernelMethodCall() { - this = API::getTopLevelMember("Kernel").getAMethodCall(_) + // Match Kernel calls using local flow, to avoid finding singleton calls on subclasses + this = DataFlow::getConstant("Kernel").getAMethodCall(_) or this.asExpr().getExpr() instanceof UnknownMethodCall and ( diff --git a/ruby/ql/lib/codeql/ruby/security/KernelOpenQuery.qll b/ruby/ql/lib/codeql/ruby/security/KernelOpenQuery.qll index 31c9055d7cc..3653fb23cee 100644 --- a/ruby/ql/lib/codeql/ruby/security/KernelOpenQuery.qll +++ b/ruby/ql/lib/codeql/ruby/security/KernelOpenQuery.qll @@ -55,7 +55,8 @@ class AmbiguousPathCall extends DataFlow::CallNode { } private predicate methodCallOnlyOnIO(DataFlow::CallNode node, string methodName) { - node = API::getTopLevelMember("IO").getAMethodCall(methodName) and + // Use local flow to find calls to 'IO' without subclasses + node = DataFlow::getConstant("IO").getAMethodCall(methodName) and not node = API::getTopLevelMember("File").getAMethodCall(methodName) // needed in e.g. opal/opal, where some calls have both paths (opal implements an own corelib) } From 61cda97163fe43abfe2886444836e823547ff6d8 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:03:25 +0200 Subject: [PATCH 174/364] Ruby: rename some call sites --- .../ruby/experimental/UnicodeBypassValidationQuery.qll | 8 ++++---- .../codeql/ruby/experimental/ZipSlipCustomizations.qll | 2 +- ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll | 4 ++-- ruby/ql/lib/codeql/ruby/security/OpenSSL.qll | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/experimental/UnicodeBypassValidationQuery.qll b/ruby/ql/lib/codeql/ruby/experimental/UnicodeBypassValidationQuery.qll index 5c24978c4c3..449e05ad9e8 100644 --- a/ruby/ql/lib/codeql/ruby/experimental/UnicodeBypassValidationQuery.qll +++ b/ruby/ql/lib/codeql/ruby/experimental/UnicodeBypassValidationQuery.qll @@ -91,19 +91,19 @@ class Configuration extends TaintTracking::Configuration { // unicode_utils exists(API::MethodAccessNode mac | mac = API::getTopLevelMember("UnicodeUtils").getMethod(["nfkd", "nfc", "nfd", "nfkc"]) and - sink = mac.getParameter(0).asSink() + sink = mac.getArgument(0).asSink() ) or // eprun exists(API::MethodAccessNode mac | mac = API::getTopLevelMember("Eprun").getMethod("normalize") and - sink = mac.getParameter(0).asSink() + sink = mac.getArgument(0).asSink() ) or // unf exists(API::MethodAccessNode mac | mac = API::getTopLevelMember("UNF").getMember("Normalizer").getMethod("normalize") and - sink = mac.getParameter(0).asSink() + sink = mac.getArgument(0).asSink() ) or // ActiveSupport::Multibyte::Chars @@ -113,7 +113,7 @@ class Configuration extends TaintTracking::Configuration { .getMember("Multibyte") .getMember("Chars") .getMethod("new") - .getCallNode() and + .asCall() and n = cn.getAMethodCall("normalize") and sink = cn.getArgument(0) ) diff --git a/ruby/ql/lib/codeql/ruby/experimental/ZipSlipCustomizations.qll b/ruby/ql/lib/codeql/ruby/experimental/ZipSlipCustomizations.qll index e94cabb414c..656ceedbe2b 100644 --- a/ruby/ql/lib/codeql/ruby/experimental/ZipSlipCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/experimental/ZipSlipCustomizations.qll @@ -89,7 +89,7 @@ module ZipSlip { // If argument refers to a string object, then it's a hardcoded path and // this file is safe. not zipOpen - .getCallNode() + .asCall() .getArgument(0) .getALocalSource() .getConstantValue() diff --git a/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll b/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll index 4095beb10af..f7345b22ed1 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll @@ -24,7 +24,7 @@ module Gem { GemSpec() { this.getExtension() = "gemspec" and - specCall = API::root().getMember("Gem").getMember("Specification").getMethod("new") and + specCall = API::getTopLevelMember("Gem").getMember("Specification").getMethod("new") and specCall.getLocation().getFile() = this } @@ -42,7 +42,7 @@ module Gem { .getBlock() .getParameter(0) .getMethod(name + "=") - .getParameter(0) + .getArgument(0) .asSink() .asExpr() .getExpr() diff --git a/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll b/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll index 261a7af462f..637f7dab04a 100644 --- a/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll +++ b/ruby/ql/lib/codeql/ruby/security/OpenSSL.qll @@ -597,7 +597,7 @@ private module Digest { call = API::getTopLevelMember("OpenSSL").getMember("Digest").getMethod("new") | this = call.getReturn().getAMethodCall(["digest", "update", "<<"]) and - algo.matchesName(call.getCallNode() + algo.matchesName(call.asCall() .getArgument(0) .asExpr() .getExpr() @@ -619,7 +619,7 @@ private module Digest { Cryptography::HashingAlgorithm algo; DigestCallDirect() { - this = API::getTopLevelMember("OpenSSL").getMember("Digest").getMethod("digest").getCallNode() and + this = API::getTopLevelMember("OpenSSL").getMember("Digest").getMethod("digest").asCall() and algo.matchesName(this.getArgument(0).asExpr().getExpr().getConstantValue().getString()) } From 2ef010f1c0490c9b40b63c80767a6759e4e7d410 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:04:00 +0200 Subject: [PATCH 175/364] Ruby: update GraphQL model --- .../ql/lib/codeql/ruby/frameworks/GraphQL.qll | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/GraphQL.qll b/ruby/ql/lib/codeql/ruby/frameworks/GraphQL.qll index 8e673c4255d..98fbe241404 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/GraphQL.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/GraphQL.qll @@ -39,13 +39,8 @@ private API::Node graphQlSchema() { result = API::getTopLevelMember("GraphQL").g */ private class GraphqlRelayClassicMutationClass extends ClassDeclaration { GraphqlRelayClassicMutationClass() { - this.getSuperclassExpr() = - graphQlSchema() - .getMember("RelayClassicMutation") - .getASubclass() - .getAValueReachableFromSource() - .asExpr() - .getExpr() + this = + graphQlSchema().getMember("RelayClassicMutation").getADescendentModule().getADeclaration() } } @@ -74,13 +69,7 @@ private class GraphqlRelayClassicMutationClass extends ClassDeclaration { */ private class GraphqlSchemaResolverClass extends ClassDeclaration { GraphqlSchemaResolverClass() { - this.getSuperclassExpr() = - graphQlSchema() - .getMember("Resolver") - .getASubclass() - .getAValueReachableFromSource() - .asExpr() - .getExpr() + this = graphQlSchema().getMember("Resolver").getADescendentModule().getADeclaration() } } @@ -103,13 +92,7 @@ private string getASupportedHttpMethod() { result = ["get", "post"] } */ class GraphqlSchemaObjectClass extends ClassDeclaration { GraphqlSchemaObjectClass() { - this.getSuperclassExpr() = - graphQlSchema() - .getMember("Object") - .getASubclass() - .getAValueReachableFromSource() - .asExpr() - .getExpr() + this = graphQlSchema().getMember("Object").getADescendentModule().getADeclaration() } /** Gets a `GraphqlFieldDefinitionMethodCall` called in this class. */ From b305c13b65e7af8b81e8c8485f3b8c55faa80d64 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:04:12 +0200 Subject: [PATCH 176/364] Ruby: update SQLite3 model --- .../ql/lib/codeql/ruby/frameworks/Sqlite3.qll | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll index 70744d6fcc8..208bff8d8c9 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll @@ -15,21 +15,19 @@ private import codeql.ruby.Concepts * https://github.com/sparklemotion/sqlite3-ruby */ module Sqlite3 { + private API::Node databaseConst() { + result = API::getTopLevelMember("SQLite3").getMember("Database") + } + + private API::Node dbInstance() { + result = databaseConst().getInstance() + or + result = databaseConst().getMethod("new").getBlock().getParameter(0) + } + /** Gets a method call with a receiver that is a database instance. */ private DataFlow::CallNode getADatabaseMethodCall(string methodName) { - exists(API::Node dbInstance | - dbInstance = API::getTopLevelMember("SQLite3").getMember("Database").getInstance() and - ( - result = dbInstance.getAMethodCall(methodName) - or - // e.g. SQLite3::Database.new("foo.db") |db| { db.some_method } - exists(DataFlow::BlockNode block | - result.getMethodName() = methodName and - block = dbInstance.getAValueReachableFromSource().(DataFlow::CallNode).getBlock() and - block.getParameter(0).flowsTo(result.getReceiver()) - ) - ) - ) + result = dbInstance().getAMethodCall(methodName) } /** A prepared but unexecuted SQL statement. */ From f8ae5301a4054257213c6a922a23583f67f5da63 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:04:53 +0200 Subject: [PATCH 177/364] Ruby: update Twirp This used right-to-left evaluation for API graphs, which is not supported anymore --- ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll | 29 ++------------------ 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll index 73ef87f5fd5..a315ae100ce 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll @@ -21,38 +21,15 @@ module Twirp { this = API::getTopLevelMember("Twirp").getMember("Service").getAnInstantiation() } - /** - * Gets a local source node for the Service instantiation argument (the service handler). - */ - private DataFlow::LocalSourceNode getHandlerSource() { - result = this.getArgument(0).getALocalSource() - } - - /** - * Gets the API::Node for the service handler's class. - */ - private API::Node getAHandlerClassApiNode() { - result.getAnInstantiation() = this.getHandlerSource() - } - - /** - * Gets the AST module for the service handler's class. - */ - private Ast::Module getAHandlerClassAstNode() { - result = - this.getAHandlerClassApiNode() - .asSource() - .asExpr() - .(CfgNodes::ExprNodes::ConstantReadAccessCfgNode) - .getExpr() - .getModule() + private DataFlow::ClassNode getAHandlerClass() { + result.getAnImmediateReference().getAMethodCall("new").flowsTo(this.getArgument(0)) } /** * Gets a handler's method. */ Ast::Method getAHandlerMethod() { - result = this.getAHandlerClassAstNode().getAnInstanceMethod() + result = this.getAHandlerClass().getAnAncestor().getAnOwnInstanceMethod().asCallableAstNode() } } From 1ae41484da02a819a486c05a8428229d7e4f05f0 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:05:15 +0200 Subject: [PATCH 178/364] Ruby: Use new features in ActionMailbox model --- ruby/ql/lib/codeql/ruby/frameworks/ActionMailbox.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionMailbox.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionMailbox.qll index 13607f67926..f237e42a9a9 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionMailbox.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionMailbox.qll @@ -27,8 +27,8 @@ module ActionMailbox { Mail() { this = [ - controller().getAnInstanceSelf().getAMethodCall("inbound_email").getAMethodCall("mail"), - controller().getAnInstanceSelf().getAMethodCall("mail") + controller().trackInstance().getReturn("inbound_email").getAMethodCall("mail"), + controller().trackInstance().getAMethodCall("mail") ] } } @@ -40,7 +40,7 @@ module ActionMailbox { RemoteContent() { this = any(Mail m) - .(DataFlow::LocalSourceNode) + .track() .getAMethodCall([ "body", "to", "from", "raw_source", "subject", "from_address", "recipients_addresses", "cc_addresses", "bcc_addresses", "in_reply_to", From fbfa31937f4b479aaf99d6c369260fa483f3aa0c Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:05:57 +0200 Subject: [PATCH 179/364] Ruby: use new features in ActionMailer --- .../codeql/ruby/frameworks/ActionMailer.qll | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionMailer.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionMailer.qll index af183333d3d..4884f46aac3 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionMailer.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionMailer.qll @@ -4,12 +4,26 @@ private import codeql.ruby.AST private import codeql.ruby.ApiGraphs +private import codeql.ruby.DataFlow private import codeql.ruby.frameworks.internal.Rails /** * Provides modeling for the `ActionMailer` library. */ module ActionMailer { + private DataFlow::ClassNode actionMailerClass() { + result = + [ + DataFlow::getConstant("ActionMailer").getConstant("Base"), + // In Rails applications `ApplicationMailer` typically extends + // `ActionMailer::Base`, but we treat it separately in case the + // `ApplicationMailer` definition is not in the database. + DataFlow::getConstant("ApplicationMailer") + ].getADescendentModule() + } + + private API::Node actionMailerInstance() { result = actionMailerClass().trackInstance() } + /** * A `ClassDeclaration` for a class that extends `ActionMailer::Base`. * For example, @@ -21,33 +35,11 @@ module ActionMailer { * ``` */ class MailerClass extends ClassDeclaration { - MailerClass() { - this.getSuperclassExpr() = - [ - API::getTopLevelMember("ActionMailer").getMember("Base"), - // In Rails applications `ApplicationMailer` typically extends - // `ActionMailer::Base`, but we treat it separately in case the - // `ApplicationMailer` definition is not in the database. - API::getTopLevelMember("ApplicationMailer") - ].getASubclass().getAValueReachableFromSource().asExpr().getExpr() - } - } - - /** A method call with a `self` receiver from within a mailer class */ - private class ContextCall extends MethodCall { - private MailerClass mailerClass; - - ContextCall() { - this.getReceiver() instanceof SelfVariableAccess and - this.getEnclosingModule() = mailerClass - } - - /** Gets the mailer class containing this method. */ - MailerClass getMailerClass() { result = mailerClass } + MailerClass() { this = actionMailerClass().getADeclaration() } } /** A call to `params` from within a mailer. */ - class ParamsCall extends ContextCall, ParamsCallImpl { - ParamsCall() { this.getMethodName() = "params" } + class ParamsCall extends ParamsCallImpl { + ParamsCall() { this = actionMailerInstance().getAMethodCall("params").asExpr().getExpr() } } } From bb3b973b32aba9ab7a92f29d2781625be8d5a9e5 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:06:35 +0200 Subject: [PATCH 180/364] Ruby: use new features in ActionController --- .../ruby/frameworks/ActionController.qll | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll index 31bdc42e350..a687837f8fd 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll @@ -83,8 +83,8 @@ class ActionControllerClass extends DataFlow::ClassNode { } } -private DataFlow::LocalSourceNode actionControllerInstance() { - result = any(ActionControllerClass cls).getSelf() +private API::Node actionControllerInstance() { + result = any(ActionControllerClass cls).getSelf().track() } /** @@ -222,19 +222,19 @@ private class ActionControllerRenderToCall extends RenderToCallImpl { } } +pragma[nomagic] +private DataFlow::CallNode renderCall() { + // ActionController#render is an alias for ActionController::Renderer#render + result = + [ + any(ActionControllerClass c).trackModule().getAMethodCall("render"), + any(ActionControllerClass c).trackModule().getReturn("renderer").getAMethodCall("render") + ] +} + /** A call to `ActionController::Renderer#render`. */ private class RendererRenderCall extends RenderCallImpl { - RendererRenderCall() { - this = - [ - // ActionController#render is an alias for ActionController::Renderer#render - any(ActionControllerClass c).getAnImmediateReference().getAMethodCall("render"), - any(ActionControllerClass c) - .getAnImmediateReference() - .getAMethodCall("renderer") - .getAMethodCall("render") - ].asExpr().getExpr() - } + RendererRenderCall() { this = renderCall().asExpr().getExpr() } } /** A call to `html_escape` from within a controller. */ @@ -260,6 +260,7 @@ class RedirectToCall extends MethodCall { this = controller .getSelf() + .track() .getAMethodCall(["redirect_to", "redirect_back", "redirect_back_or_to"]) .asExpr() .getExpr() @@ -600,9 +601,7 @@ private module ParamsSummaries { * response. */ private module Response { - DataFlow::LocalSourceNode response() { - result = actionControllerInstance().getAMethodCall("response") - } + API::Node response() { result = actionControllerInstance().getReturn("response") } class BodyWrite extends DataFlow::CallNode, Http::Server::HttpResponse::Range { BodyWrite() { this = response().getAMethodCall("body=") } @@ -628,7 +627,7 @@ private module Response { HeaderWrite() { // response.header[key] = val // response.headers[key] = val - this = response().getAMethodCall(["header", "headers"]).getAMethodCall("[]=") + this = response().getReturn(["header", "headers"]).getAMethodCall("[]=") or // response.set_header(key) = val // response[header] = val @@ -673,18 +672,12 @@ private module Response { } } -private class ActionControllerLoggerInstance extends DataFlow::Node { - ActionControllerLoggerInstance() { - this = actionControllerInstance().getAMethodCall("logger") - or - any(ActionControllerLoggerInstance i).(DataFlow::LocalSourceNode).flowsTo(this) - } -} - private class ActionControllerLoggingCall extends DataFlow::CallNode, Logging::Range { ActionControllerLoggingCall() { - this.getReceiver() instanceof ActionControllerLoggerInstance and - this.getMethodName() = ["debug", "error", "fatal", "info", "unknown", "warn"] + this = + actionControllerInstance() + .getReturn("logger") + .getAMethodCall(["debug", "error", "fatal", "info", "unknown", "warn"]) } // Note: this is identical to the definition `stdlib.Logger.LoggerInfoStyleCall`. From 8bc4193ce0b61167a067cea6127453212f9a86e4 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:07:21 +0200 Subject: [PATCH 181/364] Ruby: minor overhaul of ActiveRecord model Old version had scalability issues when adding taking more interprocedural flow and inheritance into account. --- .../codeql/ruby/frameworks/ActiveRecord.qll | 265 ++++++++++-------- .../active_record/ActiveRecord.expected | 95 ++++++- .../frameworks/active_record/ActiveRecord.ql | 14 +- 3 files changed, 247 insertions(+), 127 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll index fcca078f933..f9c15a4c211 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll @@ -30,10 +30,8 @@ private predicate isBuiltInMethodForActiveRecordModelInstance(string methodName) methodName = objectInstanceMethodName() } -private API::Node activeRecordClassApiNode() { +private API::Node activeRecordBaseClass() { result = - // class Foo < ActiveRecord::Base - // class Bar < Foo [ API::getTopLevelMember("ActiveRecord").getMember("Base"), // In Rails applications `ApplicationRecord` typically extends `ActiveRecord::Base`, but we @@ -42,6 +40,46 @@ private API::Node activeRecordClassApiNode() { ] } +/** + * Gets an object with methods from the ActiveRecord query interface. + */ +private API::Node activeRecordQueryBuilder() { + result = activeRecordBaseClass() + or + result = activeRecordBaseClass().getInstance() + or + // Assume any method call might return an ActiveRecord::Relation + // These are dynamically generated + result = activeRecordQueryBuilderMethodAccess(_).getReturn() +} + +/** Gets a call targeting the ActiveRecord query interface. */ +private API::MethodAccessNode activeRecordQueryBuilderMethodAccess(string name) { + result = activeRecordQueryBuilder().getMethod(name) and + // Due to the heuristic tracking of query builder objects, add a restriction for methods with a known call target + not isUnlikelyExternalCall(result) +} + +/** Gets a call targeting the ActiveRecord query interface. */ +private DataFlow::CallNode activeRecordQueryBuilderCall(string name) { + result = activeRecordQueryBuilderMethodAccess(name).asCall() +} + +/** + * Holds if `call` is unlikely to call into an external library, since it has a possible + * call target in its enclosing module. + */ +private predicate isUnlikelyExternalCall(API::MethodAccessNode node) { + exists(DataFlow::ModuleNode mod, DataFlow::CallNode call | call = node.asCall() | + call.getATarget() = [mod.getAnOwnSingletonMethod(), mod.getAnOwnInstanceMethod()] and + call.getEnclosingMethod() = [mod.getAnOwnSingletonMethod(), mod.getAnOwnInstanceMethod()] + ) +} + +private API::Node activeRecordConnectionInstance() { + result = activeRecordBaseClass().getReturn("connection") +} + /** * A `ClassDeclaration` for a class that inherits from `ActiveRecord::Base`. For example, * @@ -55,20 +93,19 @@ private API::Node activeRecordClassApiNode() { * ``` */ class ActiveRecordModelClass extends ClassDeclaration { + private DataFlow::ClassNode cls; + ActiveRecordModelClass() { - this.getSuperclassExpr() = - activeRecordClassApiNode().getASubclass().getAValueReachableFromSource().asExpr().getExpr() + cls = activeRecordBaseClass().getADescendentModule() and this = cls.getADeclaration() } // Gets the class declaration for this class and all of its super classes - private ModuleBase getAllClassDeclarations() { - result = this.getModule().getSuperClass*().getADeclaration() - } + private ModuleBase getAllClassDeclarations() { result = cls.getAnAncestor().getADeclaration() } /** * Gets methods defined in this class that may access a field from the database. */ - Method getAPotentialFieldAccessMethod() { + deprecated Method getAPotentialFieldAccessMethod() { // It's a method on this class or one of its super classes result = this.getAllClassDeclarations().getAMethod() and // There is a value that can be returned by this method which may include field data @@ -90,58 +127,84 @@ class ActiveRecordModelClass extends ClassDeclaration { ) ) } + + /** Gets the class as a `DataFlow::ClasNode`. */ + DataFlow::ClassNode getClassNode() { result = cls } } -/** A class method call whose receiver is an `ActiveRecordModelClass`. */ -class ActiveRecordModelClassMethodCall extends MethodCall { - private ActiveRecordModelClass recvCls; +/** + * Gets a potential reference to an ActiveRecord class object. + */ +deprecated private API::Node getAnActiveRecordModelClassRef() { + result = any(ActiveRecordModelClass cls).getClassNode().trackModule() + or + // For methods with an unknown call target, assume this might be a database field, thus returning another ActiveRecord object. + // In this case we do not know which class it belongs to, which is why this predicate can't associate the reference with a specific class. + result = getAnUnknownActiveRecordModelClassCall().getReturn() +} +/** + * Gets a call performed on an ActiveRecord class object, without a known call target in the codebase. + */ +deprecated private API::MethodAccessNode getAnUnknownActiveRecordModelClassCall() { + result = getAnActiveRecordModelClassRef().getMethod(_) and + result.asCall().asExpr().getExpr() instanceof UnknownMethodCall +} + +/** + * DEPRECATED. Use `ActiveRecordModelClass.getClassNode().trackModule().getMethod()` instead. + * + * A class method call whose receiver is an `ActiveRecordModelClass`. + */ +deprecated class ActiveRecordModelClassMethodCall extends MethodCall { ActiveRecordModelClassMethodCall() { - // e.g. Foo.where(...) - recvCls.getModule() = this.getReceiver().(ConstantReadAccess).getModule() - or - // e.g. Foo.joins(:bars).where(...) - recvCls = this.getReceiver().(ActiveRecordModelClassMethodCall).getReceiverClass() - or - // e.g. self.where(...) within an ActiveRecordModelClass - this.getReceiver() instanceof SelfVariableAccess and - this.getEnclosingModule() = recvCls + this = getAnUnknownActiveRecordModelClassCall().asCall().asExpr().getExpr() } - /** The `ActiveRecordModelClass` of the receiver of this method. */ - ActiveRecordModelClass getReceiverClass() { result = recvCls } + /** Gets the `ActiveRecordModelClass` of the receiver of this method, if it can be determined. */ + ActiveRecordModelClass getReceiverClass() { + this = result.getClassNode().trackModule().getMethod(_).asCall().asExpr().getExpr() + } } -private Expr sqlFragmentArgument(MethodCall call) { - exists(string methodName | - methodName = call.getMethodName() and - ( - methodName = - [ - "delete_all", "delete_by", "destroy_all", "destroy_by", "exists?", "find_by", "find_by!", - "find_or_create_by", "find_or_create_by!", "find_or_initialize_by", "find_by_sql", "from", - "group", "having", "joins", "lock", "not", "order", "reorder", "pluck", "where", - "rewhere", "select", "reselect", "update_all" - ] and - result = call.getArgument(0) - or - methodName = "calculate" and result = call.getArgument(1) - or - methodName in ["average", "count", "maximum", "minimum", "sum", "count_by_sql"] and - result = call.getArgument(0) - or - // This format was supported until Rails 2.3.8 - methodName = ["all", "find", "first", "last"] and - result = call.getKeywordArgument("conditions") - or - methodName = "reload" and - result = call.getKeywordArgument("lock") - or - // Calls to `annotate` can be used to add block comments to SQL queries. These are potentially vulnerable to - // SQLi if user supplied input is passed in as an argument. - methodName = "annotate" and - result = call.getArgument(_) - ) +private predicate sqlFragmentArgumentInner(DataFlow::CallNode call, DataFlow::Node sink) { + call = + activeRecordQueryBuilderCall([ + "delete_all", "delete_by", "destroy_all", "destroy_by", "exists?", "find_by", "find_by!", + "find_or_create_by", "find_or_create_by!", "find_or_initialize_by", "find_by_sql", "from", + "group", "having", "joins", "lock", "not", "order", "reorder", "pluck", "where", "rewhere", + "select", "reselect", "update_all" + ]) and + sink = call.getArgument(0) + or + call = activeRecordQueryBuilderCall("calculate") and + sink = call.getArgument(1) + or + call = + activeRecordQueryBuilderCall(["average", "count", "maximum", "minimum", "sum", "count_by_sql"]) and + sink = call.getArgument(0) + or + // This format was supported until Rails 2.3.8 + call = activeRecordQueryBuilderCall(["all", "find", "first", "last"]) and + sink = call.getKeywordArgument("conditions") + or + call = activeRecordQueryBuilderCall("reload") and + sink = call.getKeywordArgument("lock") + or + // Calls to `annotate` can be used to add block comments to SQL queries. These are potentially vulnerable to + // SQLi if user supplied input is passed in as an argument. + call = activeRecordQueryBuilderCall("annotate") and + sink = call.getArgument(_) + or + call = activeRecordConnectionInstance().getAMethodCall("execute") and + sink = call.getArgument(0) +} + +private predicate sqlFragmentArgument(DataFlow::CallNode call, DataFlow::Node sink) { + exists(DataFlow::Node arg | + sqlFragmentArgumentInner(call, arg) and + sink = [arg, arg.(DataFlow::ArrayLiteralNode).getElement(0)] and + unsafeSqlExpr(sink.asExpr().getExpr()) ) } @@ -162,6 +225,8 @@ private predicate unsafeSqlExpr(Expr sqlFragmentExpr) { } /** + * DEPRECATED. Use the `SqlExecution` concept or `ActiveRecordSqlExecutionRange`. + * * A method call that may result in executing unintended user-controlled SQL * queries if the `getSqlFragmentSinkArgument()` expression is tainted by * unsanitized user-controlled input. For example, supposing that `User` is an @@ -175,55 +240,32 @@ private predicate unsafeSqlExpr(Expr sqlFragmentExpr) { * as `"') OR 1=1 --"` could result in the application looking up all users * rather than just one with a matching name. */ -class PotentiallyUnsafeSqlExecutingMethodCall extends ActiveRecordModelClassMethodCall { - // The SQL fragment argument itself - private Expr sqlFragmentExpr; +deprecated class PotentiallyUnsafeSqlExecutingMethodCall extends ActiveRecordModelClassMethodCall { + private DataFlow::CallNode call; PotentiallyUnsafeSqlExecutingMethodCall() { - exists(Expr arg | - arg = sqlFragmentArgument(this) and - unsafeSqlExpr(sqlFragmentExpr) and - ( - sqlFragmentExpr = arg - or - sqlFragmentExpr = arg.(ArrayLiteral).getElement(0) - ) and - // Check that method has not been overridden - not exists(SingletonMethod m | - m.getName() = this.getMethodName() and - m.getOuterScope() = this.getReceiverClass() - ) - ) + call.asExpr().getExpr() = this and sqlFragmentArgument(call, _) } /** * Gets the SQL fragment argument of this method call. */ - Expr getSqlFragmentSinkArgument() { result = sqlFragmentExpr } + Expr getSqlFragmentSinkArgument() { + exists(DataFlow::Node sink | + sqlFragmentArgument(call, sink) and result = sink.asExpr().getExpr() + ) + } } /** - * An `SqlExecution::Range` for an argument to a - * `PotentiallyUnsafeSqlExecutingMethodCall` that may be vulnerable to being - * controlled by user input. + * A SQL execution arising from a call to the ActiveRecord library. */ class ActiveRecordSqlExecutionRange extends SqlExecution::Range { - ActiveRecordSqlExecutionRange() { - exists(PotentiallyUnsafeSqlExecutingMethodCall mc | - this.asExpr().getNode() = mc.getSqlFragmentSinkArgument() - ) - or - this = activeRecordConnectionInstance().getAMethodCall("execute").getArgument(0) and - unsafeSqlExpr(this.asExpr().getExpr()) - } + ActiveRecordSqlExecutionRange() { sqlFragmentArgument(_, this) } override DataFlow::Node getSql() { result = this } } -private API::Node activeRecordConnectionInstance() { - result = activeRecordClassApiNode().getReturn("connection") -} - // TODO: model `ActiveRecord` sanitizers // https://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html /** @@ -241,15 +283,8 @@ abstract class ActiveRecordModelInstantiation extends OrmInstantiation::Range, override predicate methodCallMayAccessField(string methodName) { // The method is not a built-in, and... not isBuiltInMethodForActiveRecordModelInstance(methodName) and - ( - // ...There is no matching method definition in the class, or... - not exists(this.getClass().getMethod(methodName)) - or - // ...the called method can access a field. - exists(Method m | m = this.getClass().getAPotentialFieldAccessMethod() | - m.getName() = methodName - ) - ) + // ...There is no matching method definition in the class + not exists(this.getClass().getMethod(methodName)) } } @@ -317,21 +352,10 @@ private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation } // A `self` reference that may resolve to an active record model object -private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInstantiation, - DataFlow::SelfParameterNode -{ +private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInstantiation { private ActiveRecordModelClass cls; - ActiveRecordModelClassSelfReference() { - exists(MethodBase m | - m = this.getCallable() and - m.getEnclosingModule() = cls and - m = cls.getAMethod() - ) and - // In a singleton method, `self` refers to the class itself rather than an - // instance of that class - not this.getSelfVariable().getDeclaringScope() instanceof SingletonMethod - } + ActiveRecordModelClassSelfReference() { this = cls.getClassNode().getAnOwnInstanceSelf() } final override ActiveRecordModelClass getClass() { result = cls } } @@ -342,7 +366,7 @@ private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInsta class ActiveRecordInstance extends DataFlow::Node { private ActiveRecordModelInstantiation instantiation; - ActiveRecordInstance() { this = instantiation or instantiation.flowsTo(this) } + ActiveRecordInstance() { this = instantiation.track().getAValueReachableFromSource() } /** Gets the `ActiveRecordModelClass` that this is an instance of. */ ActiveRecordModelClass getClass() { result = instantiation.getClass() } @@ -380,12 +404,12 @@ private module Persistence { /** A call to e.g. `User.create(name: "foo")` */ private class CreateLikeCall extends DataFlow::CallNode, PersistentWriteAccess::Range { CreateLikeCall() { - exists(this.asExpr().getExpr().(ActiveRecordModelClassMethodCall).getReceiverClass()) and - this.getMethodName() = - [ - "create", "create!", "create_or_find_by", "create_or_find_by!", "find_or_create_by", - "find_or_create_by!", "insert", "insert!" - ] + this = + activeRecordBaseClass() + .getAMethodCall([ + "create", "create!", "create_or_find_by", "create_or_find_by!", "find_or_create_by", + "find_or_create_by!", "insert", "insert!" + ]) } override DataFlow::Node getValue() { @@ -402,8 +426,7 @@ private module Persistence { /** A call to e.g. `User.update(1, name: "foo")` */ private class UpdateLikeClassMethodCall extends DataFlow::CallNode, PersistentWriteAccess::Range { UpdateLikeClassMethodCall() { - exists(this.asExpr().getExpr().(ActiveRecordModelClassMethodCall).getReceiverClass()) and - this.getMethodName() = ["update", "update!", "upsert"] + this = activeRecordBaseClass().getAMethodCall(["update", "update!", "upsert"]) } override DataFlow::Node getValue() { @@ -448,10 +471,7 @@ private module Persistence { * ``` */ private class TouchAllCall extends DataFlow::CallNode, PersistentWriteAccess::Range { - TouchAllCall() { - exists(this.asExpr().getExpr().(ActiveRecordModelClassMethodCall).getReceiverClass()) and - this.getMethodName() = "touch_all" - } + TouchAllCall() { this = activeRecordQueryBuilderCall("touch_all") } override DataFlow::Node getValue() { result = this.getKeywordArgument("time") } } @@ -461,8 +481,7 @@ private module Persistence { private ExprNodes::ArrayLiteralCfgNode arr; InsertAllLikeCall() { - exists(this.asExpr().getExpr().(ActiveRecordModelClassMethodCall).getReceiverClass()) and - this.getMethodName() = ["insert_all", "insert_all!", "upsert_all"] and + this = activeRecordBaseClass().getAMethodCall(["insert_all", "insert_all!", "upsert_all"]) and arr = this.getArgument(0).asExpr() } diff --git a/ruby/ql/test/library-tests/frameworks/active_record/ActiveRecord.expected b/ruby/ql/test/library-tests/frameworks/active_record/ActiveRecord.expected index 0374a54c0c1..a3ee4ebebf5 100644 --- a/ruby/ql/test/library-tests/frameworks/active_record/ActiveRecord.expected +++ b/ruby/ql/test/library-tests/frameworks/active_record/ActiveRecord.expected @@ -10,6 +10,7 @@ activeRecordInstances | ActiveRecord.rb:9:5:9:68 | call to find | | ActiveRecord.rb:13:5:13:40 | call to find_by | | ActiveRecord.rb:13:5:13:46 | call to users | +| ActiveRecord.rb:35:5:35:51 | call to authenticate | | ActiveRecord.rb:36:5:36:30 | call to find_by_name | | ActiveRecord.rb:55:5:57:7 | if ... | | ActiveRecord.rb:55:43:56:40 | then ... | @@ -107,12 +108,14 @@ activeRecordSqlExecutionRanges | ActiveRecord.rb:19:16:19:24 | condition | | ActiveRecord.rb:28:30:28:44 | ...[...] | | ActiveRecord.rb:29:20:29:42 | "id = '#{...}'" | +| ActiveRecord.rb:30:21:30:45 | call to [] | | ActiveRecord.rb:30:22:30:44 | "id = '#{...}'" | | ActiveRecord.rb:31:16:31:21 | <<-SQL | | ActiveRecord.rb:34:20:34:47 | "user.id = '#{...}'" | | ActiveRecord.rb:46:20:46:32 | ... + ... | | ActiveRecord.rb:52:16:52:28 | "name #{...}" | | ActiveRecord.rb:56:20:56:39 | "username = #{...}" | +| ActiveRecord.rb:68:21:68:44 | ...[...] | | ActiveRecord.rb:106:27:106:76 | "this is an unsafe annotation:..." | activeRecordModelClassMethodCalls | ActiveRecord.rb:2:3:2:17 | call to has_many | @@ -127,7 +130,6 @@ activeRecordModelClassMethodCalls | ActiveRecord.rb:31:5:31:35 | call to where | | ActiveRecord.rb:34:5:34:14 | call to where | | ActiveRecord.rb:34:5:34:48 | call to not | -| ActiveRecord.rb:35:5:35:51 | call to authenticate | | ActiveRecord.rb:36:5:36:30 | call to find_by_name | | ActiveRecord.rb:37:5:37:36 | call to not_a_find_by_method | | ActiveRecord.rb:46:5:46:33 | call to delete_by | @@ -135,7 +137,6 @@ activeRecordModelClassMethodCalls | ActiveRecord.rb:56:7:56:40 | call to find_by | | ActiveRecord.rb:60:5:60:33 | call to find_by | | ActiveRecord.rb:62:5:62:34 | call to find | -| ActiveRecord.rb:68:5:68:45 | call to delete_by | | ActiveRecord.rb:72:5:72:24 | call to create | | ActiveRecord.rb:76:5:76:66 | call to create | | ActiveRecord.rb:80:5:80:68 | call to create | @@ -152,6 +153,96 @@ activeRecordModelClassMethodCalls | associations.rb:12:3:12:32 | call to has_and_belongs_to_many | | associations.rb:16:3:16:18 | call to belongs_to | | associations.rb:19:11:19:20 | call to new | +| associations.rb:21:9:21:21 | call to posts | +| associations.rb:21:9:21:28 | call to create | +| associations.rb:23:12:23:25 | call to comments | +| associations.rb:23:12:23:32 | call to create | +| associations.rb:25:11:25:22 | call to author | +| associations.rb:27:9:27:21 | call to posts | +| associations.rb:27:9:27:28 | call to create | +| associations.rb:29:1:29:13 | call to posts | +| associations.rb:29:1:29:22 | ... << ... | +| associations.rb:31:1:31:12 | call to author= | +| associations.rb:35:1:35:14 | call to comments | +| associations.rb:35:1:35:21 | call to create | +| associations.rb:35:1:35:28 | call to create | +| associations.rb:37:1:37:13 | call to posts | +| associations.rb:37:1:37:20 | call to reload | +| associations.rb:37:1:37:27 | call to create | +| associations.rb:39:1:39:15 | call to build_tag | +| associations.rb:40:1:40:15 | call to build_tag | +| associations.rb:42:1:42:13 | call to posts | +| associations.rb:42:1:42:25 | call to push | +| associations.rb:43:1:43:13 | call to posts | +| associations.rb:43:1:43:27 | call to concat | +| associations.rb:44:1:44:13 | call to posts | +| associations.rb:44:1:44:19 | call to build | +| associations.rb:45:1:45:13 | call to posts | +| associations.rb:45:1:45:20 | call to create | +| associations.rb:46:1:46:13 | call to posts | +| associations.rb:46:1:46:21 | call to create! | +| associations.rb:47:1:47:13 | call to posts | +| associations.rb:47:1:47:20 | call to delete | +| associations.rb:48:1:48:13 | call to posts | +| associations.rb:48:1:48:24 | call to delete_all | +| associations.rb:49:1:49:13 | call to posts | +| associations.rb:49:1:49:21 | call to destroy | +| associations.rb:50:1:50:13 | call to posts | +| associations.rb:50:1:50:25 | call to destroy_all | +| associations.rb:51:1:51:13 | call to posts | +| associations.rb:51:1:51:22 | call to distinct | +| associations.rb:51:1:51:36 | call to find | +| associations.rb:52:1:52:13 | call to posts | +| associations.rb:52:1:52:19 | call to reset | +| associations.rb:52:1:52:33 | call to find | +| associations.rb:53:1:53:13 | call to posts | +| associations.rb:53:1:53:20 | call to reload | +| associations.rb:53:1:53:34 | call to find | +activeRecordModelClassMethodCallsReplacement +| ActiveRecord.rb:1:1:3:3 | UserGroup | ActiveRecord.rb:2:3:2:17 | call to has_many | +| ActiveRecord.rb:1:1:3:3 | UserGroup | ActiveRecord.rb:13:5:13:40 | call to find_by | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:6:3:6:24 | call to belongs_to | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:9:5:9:68 | call to find | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:19:5:19:25 | call to destroy_by | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:28:5:28:45 | call to calculate | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:29:5:29:43 | call to delete_by | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:30:5:30:46 | call to destroy_by | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:31:5:31:35 | call to where | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:34:5:34:14 | call to where | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:35:5:35:51 | call to authenticate | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:36:5:36:30 | call to find_by_name | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:37:5:37:36 | call to not_a_find_by_method | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:46:5:46:33 | call to delete_by | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:52:5:52:29 | call to order | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:56:7:56:40 | call to find_by | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:60:5:60:33 | call to find_by | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:62:5:62:34 | call to find | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:68:5:68:45 | call to delete_by | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:72:5:72:24 | call to create | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:76:5:76:66 | call to create | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:80:5:80:68 | call to create | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:84:5:84:16 | call to create | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:88:5:88:27 | call to update | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:92:5:92:69 | call to update | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:96:5:96:71 | call to update | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:102:13:102:54 | call to annotate | +| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:106:13:106:77 | call to annotate | +| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:19:5:19:25 | call to destroy_by | +| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:68:5:68:45 | call to delete_by | +| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:72:5:72:24 | call to create | +| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:76:5:76:66 | call to create | +| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:80:5:80:68 | call to create | +| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:84:5:84:16 | call to create | +| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:88:5:88:27 | call to update | +| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:92:5:92:69 | call to update | +| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:96:5:96:71 | call to update | +| associations.rb:1:1:3:3 | Author | associations.rb:2:3:2:17 | call to has_many | +| associations.rb:1:1:3:3 | Author | associations.rb:19:11:19:20 | call to new | +| associations.rb:5:1:9:3 | Post | associations.rb:6:3:6:20 | call to belongs_to | +| associations.rb:5:1:9:3 | Post | associations.rb:7:3:7:20 | call to has_many | +| associations.rb:5:1:9:3 | Post | associations.rb:8:3:8:31 | call to has_and_belongs_to_many | +| associations.rb:11:1:13:3 | Tag | associations.rb:12:3:12:32 | call to has_and_belongs_to_many | +| associations.rb:15:1:17:3 | Comment | associations.rb:16:3:16:18 | call to belongs_to | potentiallyUnsafeSqlExecutingMethodCall | ActiveRecord.rb:9:5:9:68 | call to find | | ActiveRecord.rb:19:5:19:25 | call to destroy_by | diff --git a/ruby/ql/test/library-tests/frameworks/active_record/ActiveRecord.ql b/ruby/ql/test/library-tests/frameworks/active_record/ActiveRecord.ql index 731679e437b..348ca1456e2 100644 --- a/ruby/ql/test/library-tests/frameworks/active_record/ActiveRecord.ql +++ b/ruby/ql/test/library-tests/frameworks/active_record/ActiveRecord.ql @@ -9,9 +9,19 @@ query predicate activeRecordInstances(ActiveRecordInstance i) { any() } query predicate activeRecordSqlExecutionRanges(ActiveRecordSqlExecutionRange range) { any() } -query predicate activeRecordModelClassMethodCalls(ActiveRecordModelClassMethodCall call) { any() } +deprecated query predicate activeRecordModelClassMethodCalls(ActiveRecordModelClassMethodCall call) { + any() +} -query predicate potentiallyUnsafeSqlExecutingMethodCall(PotentiallyUnsafeSqlExecutingMethodCall call) { +query predicate activeRecordModelClassMethodCallsReplacement( + ActiveRecordModelClass cls, DataFlow::CallNode call +) { + call = cls.getClassNode().trackModule().getAMethodCall(_) +} + +deprecated query predicate potentiallyUnsafeSqlExecutingMethodCall( + PotentiallyUnsafeSqlExecutingMethodCall call +) { any() } From e3a04499f630e19b90fb0b3aeef2a64c9edb4368 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:07:45 +0200 Subject: [PATCH 182/364] Ruby: minor overhaul of ActiveResource model --- .../codeql/ruby/frameworks/ActiveResource.qll | 196 ++++++++---------- .../active_resource/ActiveResource.expected | 10 + .../active_resource/ActiveResource.ql | 15 +- 3 files changed, 112 insertions(+), 109 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActiveResource.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActiveResource.qll index 96219915770..9f0e0f4b859 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActiveResource.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActiveResource.qll @@ -18,8 +18,12 @@ module ActiveResource { * An ActiveResource model class. This is any (transitive) subclass of ActiveResource. */ pragma[nomagic] - private API::Node modelApiNode() { - result = API::getTopLevelMember("ActiveResource").getMember("Base").getASubclass() + private API::Node activeResourceBaseClass() { + result = API::getTopLevelMember("ActiveResource").getMember("Base") + } + + private DataFlow::ClassNode activeResourceClass() { + result = activeResourceBaseClass().getADescendentModule() } /** @@ -30,16 +34,8 @@ module ActiveResource { * end * ``` */ - class ModelClass extends ClassDeclaration { - API::Node model; - - ModelClass() { - model = modelApiNode() and - this.getSuperclassExpr() = model.getAValueReachableFromSource().asExpr().getExpr() - } - - /** Gets the API node for this model */ - API::Node getModelApiNode() { result = model } + class ModelClassNode extends DataFlow::ClassNode { + ModelClassNode() { this = activeResourceClass() } /** Gets a call to `site=`, which sets the base URL for this model. */ SiteAssignCall getASiteAssignment() { result.getModelClass() = this } @@ -49,6 +45,46 @@ module ActiveResource { c = this.getASiteAssignment() and c.disablesCertificateValidation() } + + /** Gets a method call on this class that returns an instance of the class. */ + private DataFlow::CallNode getAChainedCall() { + result.(FindCall).getModelClass() = this + or + result.(CreateCall).getModelClass() = this + or + result.(CustomHttpCall).getModelClass() = this + or + result.(CollectionCall).getCollection().getModelClass() = this and + result.getMethodName() = ["first", "last"] + } + + /** Gets an API node referring to an instance of this class. */ + API::Node getAnInstanceReference() { + result = this.trackInstance() + or + result = this.getAChainedCall().track() + } + } + + /** DEPRECATED. Use `ModelClassNode` instead. */ + deprecated class ModelClass extends ClassDeclaration { + private ModelClassNode cls; + + ModelClass() { this = cls.getADeclaration() } + + /** Gets the class for which this is a declaration. */ + ModelClassNode getClassNode() { result = cls } + + /** Gets the API node for this class object. */ + deprecated API::Node getModelApiNode() { result = cls.trackModule() } + + /** Gets a call to `site=`, which sets the base URL for this model. */ + SiteAssignCall getASiteAssignment() { result = cls.getASiteAssignment() } + + /** Holds if `c` sets a base URL which does not use HTTPS. */ + predicate disablesCertificateValidation(SiteAssignCall c) { + cls.disablesCertificateValidation(c) + } } /** @@ -62,25 +98,20 @@ module ActiveResource { * ``` */ class ModelClassMethodCall extends DataFlow::CallNode { - API::Node model; + private ModelClassNode cls; - ModelClassMethodCall() { - model = modelApiNode() and - this = classMethodCall(model, _) - } + ModelClassMethodCall() { this = cls.trackModule().getAMethodCall(_) } /** Gets the model class for this call. */ - ModelClass getModelClass() { result.getModelApiNode() = model } + ModelClassNode getModelClass() { result = cls } } /** * A call to `site=` on an ActiveResource model class. * This sets the base URL for all HTTP requests made by this class. */ - private class SiteAssignCall extends DataFlow::CallNode { - API::Node model; - - SiteAssignCall() { model = modelApiNode() and this = classMethodCall(model, "site=") } + private class SiteAssignCall extends ModelClassMethodCall { + SiteAssignCall() { this.getMethodName() = "site=" } /** * Gets a node that contributes to the URLs used for HTTP requests by the parent @@ -88,12 +119,10 @@ module ActiveResource { */ DataFlow::Node getAUrlPart() { result = this.getArgument(0) } - /** Gets the model class for this call. */ - ModelClass getModelClass() { result.getModelApiNode() = model } - /** Holds if this site value specifies HTTP rather than HTTPS. */ predicate disablesCertificateValidation() { this.getAUrlPart() + // TODO: We should not need all this just to get the string value .asExpr() .(ExprNodes::AssignExprCfgNode) .getRhs() @@ -141,87 +170,70 @@ module ActiveResource { } /** + * DEPRECATED. Use `ModelClassNode.getAnInstanceReference()` instead. + * * An ActiveResource model object. */ - class ModelInstance extends DataFlow::Node { - ModelClass cls; + deprecated class ModelInstance extends DataFlow::Node { + private ModelClassNode cls; - ModelInstance() { - exists(API::Node model | model = modelApiNode() | - this = model.getInstance().getAValueReachableFromSource() and - cls.getModelApiNode() = model - ) - or - exists(FindCall call | call.flowsTo(this) | cls = call.getModelClass()) - or - exists(CreateCall call | call.flowsTo(this) | cls = call.getModelClass()) - or - exists(CustomHttpCall call | call.flowsTo(this) | cls = call.getModelClass()) - or - exists(CollectionCall call | - call.getMethodName() = ["first", "last"] and - call.flowsTo(this) - | - cls = call.getCollection().getModelClass() - ) - } + ModelInstance() { this = cls.getAnInstanceReference().getAValueReachableFromSource() } /** Gets the model class for this instance. */ - ModelClass getModelClass() { result = cls } + ModelClassNode getModelClass() { result = cls } } /** * A call to a method on an ActiveResource model object. */ class ModelInstanceMethodCall extends DataFlow::CallNode { - ModelInstance i; + private ModelClassNode cls; - ModelInstanceMethodCall() { this.getReceiver() = i } + ModelInstanceMethodCall() { this = cls.getAnInstanceReference().getAMethodCall(_) } /** Gets the model instance for this call. */ - ModelInstance getInstance() { result = i } + deprecated ModelInstance getInstance() { result = this.getReceiver() } /** Gets the model class for this call. */ - ModelClass getModelClass() { result = i.getModelClass() } + ModelClassNode getModelClass() { result = cls } } /** - * A collection of ActiveResource model objects. + * DEPRECATED. Use `CollectionSource` instead. + * + * A data flow node that may refer to a collection of ActiveResource model objects. */ - class Collection extends DataFlow::Node { - ModelClassMethodCall classMethodCall; + deprecated class Collection extends DataFlow::Node { + Collection() { this = any(CollectionSource src).track().getAValueReachableFromSource() } + } - Collection() { - classMethodCall.flowsTo(this) and - ( - classMethodCall.getMethodName() = "all" - or - classMethodCall.getMethodName() = "find" and - classMethodCall.getArgument(0).asExpr().getConstantValue().isStringlikeValue("all") - ) + /** + * A call that returns a collection of ActiveResource model objects. + */ + class CollectionSource extends ModelClassMethodCall { + CollectionSource() { + this.getMethodName() = "all" + or + this.getArgument(0).asExpr().getConstantValue().isStringlikeValue("all") } - - /** Gets the model class for this collection. */ - ModelClass getModelClass() { result = classMethodCall.getModelClass() } } /** * A method call on a collection. */ class CollectionCall extends DataFlow::CallNode { - CollectionCall() { this.getReceiver() instanceof Collection } + private CollectionSource collection; + + CollectionCall() { this = collection.track().getAMethodCall(_) } /** Gets the collection for this call. */ - Collection getCollection() { result = this.getReceiver() } + CollectionSource getCollection() { result = collection } } private class ModelClassMethodCallAsHttpRequest extends Http::Client::Request::Range, ModelClassMethodCall { - ModelClass cls; - ModelClassMethodCallAsHttpRequest() { - this.getModelClass() = cls and this.getMethodName() = ["all", "build", "create", "create!", "find", "first", "last"] } @@ -230,12 +242,14 @@ module ActiveResource { override predicate disablesCertificateValidation( DataFlow::Node disablingNode, DataFlow::Node argumentOrigin ) { - cls.disablesCertificateValidation(disablingNode) and + this.getModelClass().disablesCertificateValidation(disablingNode) and // TODO: highlight real argument origin argumentOrigin = disablingNode } - override DataFlow::Node getAUrlPart() { result = cls.getASiteAssignment().getAUrlPart() } + override DataFlow::Node getAUrlPart() { + result = this.getModelClass().getASiteAssignment().getAUrlPart() + } override DataFlow::Node getResponseBody() { result = this } } @@ -243,10 +257,7 @@ module ActiveResource { private class ModelInstanceMethodCallAsHttpRequest extends Http::Client::Request::Range, ModelInstanceMethodCall { - ModelClass cls; - ModelInstanceMethodCallAsHttpRequest() { - this.getModelClass() = cls and this.getMethodName() = [ "exists?", "reload", "save", "save!", "destroy", "delete", "get", "patch", "post", "put", @@ -259,42 +270,15 @@ module ActiveResource { override predicate disablesCertificateValidation( DataFlow::Node disablingNode, DataFlow::Node argumentOrigin ) { - cls.disablesCertificateValidation(disablingNode) and + this.getModelClass().disablesCertificateValidation(disablingNode) and // TODO: highlight real argument origin argumentOrigin = disablingNode } - override DataFlow::Node getAUrlPart() { result = cls.getASiteAssignment().getAUrlPart() } + override DataFlow::Node getAUrlPart() { + result = this.getModelClass().getASiteAssignment().getAUrlPart() + } override DataFlow::Node getResponseBody() { result = this } } - - /** - * A call to a class method. - * - * TODO: is this general enough to be useful elsewhere? - * - * Examples: - * ```rb - * class A - * def self.m; end - * - * m # call - * end - * - * A.m # call - * ``` - */ - private DataFlow::CallNode classMethodCall(API::Node classNode, string methodName) { - // A.m - result = classNode.getAMethodCall(methodName) - or - // class A - // A.m - // end - result.getReceiver().asExpr() instanceof ExprNodes::SelfVariableAccessCfgNode and - result.asExpr().getExpr().getEnclosingModule().(ClassDeclaration).getSuperclassExpr() = - classNode.getAValueReachableFromSource().asExpr().getExpr() and - result.getMethodName() = methodName - } } diff --git a/ruby/ql/test/library-tests/frameworks/active_resource/ActiveResource.expected b/ruby/ql/test/library-tests/frameworks/active_resource/ActiveResource.expected index a55946c1852..e6d3b056971 100644 --- a/ruby/ql/test/library-tests/frameworks/active_resource/ActiveResource.expected +++ b/ruby/ql/test/library-tests/frameworks/active_resource/ActiveResource.expected @@ -33,6 +33,13 @@ modelInstances | active_resource.rb:26:9:26:14 | people | | active_resource.rb:26:9:26:20 | call to first | | active_resource.rb:27:1:27:5 | alice | +modelInstancesAsSource +| active_resource.rb:1:1:3:3 | Person | active_resource.rb:5:9:5:33 | call to new | +| active_resource.rb:1:1:3:3 | Person | active_resource.rb:8:9:8:22 | call to find | +| active_resource.rb:1:1:3:3 | Person | active_resource.rb:16:1:16:23 | call to new | +| active_resource.rb:1:1:3:3 | Person | active_resource.rb:18:1:18:22 | call to get | +| active_resource.rb:1:1:3:3 | Person | active_resource.rb:24:10:24:26 | call to find | +| active_resource.rb:1:1:3:3 | Person | active_resource.rb:26:9:26:20 | call to first | modelInstanceMethodCalls | active_resource.rb:6:1:6:10 | call to save | | active_resource.rb:9:1:9:13 | call to address= | @@ -50,3 +57,6 @@ collections | active_resource.rb:24:1:24:26 | ... = ... | | active_resource.rb:24:10:24:26 | call to find | | active_resource.rb:26:9:26:14 | people | +collectionSources +| active_resource.rb:23:10:23:19 | call to all | +| active_resource.rb:24:10:24:26 | call to find | diff --git a/ruby/ql/test/library-tests/frameworks/active_resource/ActiveResource.ql b/ruby/ql/test/library-tests/frameworks/active_resource/ActiveResource.ql index 1f2fd1efcf1..f1898ddbc98 100644 --- a/ruby/ql/test/library-tests/frameworks/active_resource/ActiveResource.ql +++ b/ruby/ql/test/library-tests/frameworks/active_resource/ActiveResource.ql @@ -3,7 +3,8 @@ import codeql.ruby.DataFlow import codeql.ruby.frameworks.ActiveResource query predicate modelClasses( - ActiveResource::ModelClass c, DataFlow::Node siteAssignCall, boolean disablesCertificateValidation + ActiveResource::ModelClassNode c, DataFlow::Node siteAssignCall, + boolean disablesCertificateValidation ) { c.getASiteAssignment() = siteAssignCall and if c.disablesCertificateValidation(siteAssignCall) @@ -13,8 +14,16 @@ query predicate modelClasses( query predicate modelClassMethodCalls(ActiveResource::ModelClassMethodCall c) { any() } -query predicate modelInstances(ActiveResource::ModelInstance c) { any() } +deprecated query predicate modelInstances(ActiveResource::ModelInstance c) { any() } + +query predicate modelInstancesAsSource( + ActiveResource::ModelClassNode cls, DataFlow::LocalSourceNode node +) { + node = cls.getAnInstanceReference().asSource() +} query predicate modelInstanceMethodCalls(ActiveResource::ModelInstanceMethodCall c) { any() } -query predicate collections(ActiveResource::Collection c) { any() } +deprecated query predicate collections(ActiveResource::Collection c) { any() } + +query predicate collectionSources(ActiveResource::CollectionSource c) { any() } From ce0073b30c7bad217de5c62431ec6535645dce25 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:13:07 +0200 Subject: [PATCH 183/364] Ruby: update StoredXSS test results These results were previously flagged for the wrong reason. Calls to a user-define method were seen as ORM calls. The real source is inside the user-defined method, but we miss that due to lack of 'self' handling in ORM tracking. --- .../query-tests/security/cwe-079/StoredXSS.expected | 10 ---------- .../cwe-079/app/views/foo/stores/show.html.erb | 6 +++--- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.expected b/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.expected index 0eaf24029ef..460c7da3145 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.expected +++ b/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.expected @@ -3,7 +3,6 @@ edges | app/controllers/foo/stores_controller.rb:8:5:8:6 | dt | app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/controllers/foo/stores_controller.rb:8:5:8:6 | dt | | app/controllers/foo/stores_controller.rb:9:22:9:23 | dt | app/views/foo/stores/show.html.erb:37:3:37:16 | @instance_text | -| app/controllers/foo/stores_controller.rb:12:28:12:48 | call to raw_name | app/views/foo/stores/show.html.erb:82:5:82:24 | @other_user_raw_name | | app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:2:9:2:20 | call to display_text | | app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:5:9:5:21 | call to local_assigns [element :display_text] | | app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:9:9:9:21 | call to local_assigns [element :display_text] | @@ -22,7 +21,6 @@ nodes | app/controllers/foo/stores_controller.rb:8:5:8:6 | dt | semmle.label | dt | | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | semmle.label | call to read | | app/controllers/foo/stores_controller.rb:9:22:9:23 | dt | semmle.label | dt | -| app/controllers/foo/stores_controller.rb:12:28:12:48 | call to raw_name | semmle.label | call to raw_name | | app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | semmle.label | dt | | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | semmle.label | call to display_text | | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | @@ -39,11 +37,7 @@ nodes | app/views/foo/stores/show.html.erb:40:64:40:87 | ... + ... | semmle.label | ... + ... | | app/views/foo/stores/show.html.erb:40:76:40:87 | call to display_text | semmle.label | call to display_text | | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | semmle.label | call to handle | -| app/views/foo/stores/show.html.erb:49:5:49:18 | call to raw_name | semmle.label | call to raw_name | | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | semmle.label | call to handle | -| app/views/foo/stores/show.html.erb:69:3:69:20 | call to raw_name | semmle.label | call to raw_name | -| app/views/foo/stores/show.html.erb:79:5:79:22 | call to display_name | semmle.label | call to display_name | -| app/views/foo/stores/show.html.erb:82:5:82:24 | @other_user_raw_name | semmle.label | @other_user_raw_name | | app/views/foo/stores/show.html.erb:86:3:86:29 | call to sprintf | semmle.label | call to sprintf | | app/views/foo/stores/show.html.erb:86:17:86:28 | call to handle | semmle.label | call to handle | subpaths @@ -57,9 +51,5 @@ subpaths | app/views/foo/stores/show.html.erb:32:3:32:14 | call to display_text | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/stores/show.html.erb:32:3:32:14 | call to display_text | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value | | app/views/foo/stores/show.html.erb:37:3:37:16 | @instance_text | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/stores/show.html.erb:37:3:37:16 | @instance_text | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value | | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | stored value | -| app/views/foo/stores/show.html.erb:49:5:49:18 | call to raw_name | app/views/foo/stores/show.html.erb:49:5:49:18 | call to raw_name | app/views/foo/stores/show.html.erb:49:5:49:18 | call to raw_name | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:49:5:49:18 | call to raw_name | stored value | | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | stored value | -| app/views/foo/stores/show.html.erb:69:3:69:20 | call to raw_name | app/views/foo/stores/show.html.erb:69:3:69:20 | call to raw_name | app/views/foo/stores/show.html.erb:69:3:69:20 | call to raw_name | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:69:3:69:20 | call to raw_name | stored value | -| app/views/foo/stores/show.html.erb:79:5:79:22 | call to display_name | app/views/foo/stores/show.html.erb:79:5:79:22 | call to display_name | app/views/foo/stores/show.html.erb:79:5:79:22 | call to display_name | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:79:5:79:22 | call to display_name | stored value | -| app/views/foo/stores/show.html.erb:82:5:82:24 | @other_user_raw_name | app/controllers/foo/stores_controller.rb:12:28:12:48 | call to raw_name | app/views/foo/stores/show.html.erb:82:5:82:24 | @other_user_raw_name | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:12:28:12:48 | call to raw_name | stored value | | app/views/foo/stores/show.html.erb:86:3:86:29 | call to sprintf | app/views/foo/stores/show.html.erb:86:17:86:28 | call to handle | app/views/foo/stores/show.html.erb:86:3:86:29 | call to sprintf | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:86:17:86:28 | call to handle | stored value | diff --git a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb index 29656a15a3d..d8afec1c432 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb +++ b/ruby/ql/test/query-tests/security/cwe-079/app/views/foo/stores/show.html.erb @@ -63,7 +63,7 @@ some_user.handle.html_safe %> -<%# BAD: Indirect to a database value without escaping %> +<%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %> <%= some_user = User.find 1 some_user.raw_name.html_safe @@ -75,10 +75,10 @@ some_user.handle %> -<%# BAD: Indirect to a database value without escaping %> +<%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %> <%= @user.display_name.html_safe %> -<%# BAD: Indirect to a database value without escaping %> +<%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %> <%= @other_user_raw_name.html_safe %> <%# BAD: Kernel.sprintf is a taint-step %> From f392af220b0ae2562260a81140e28db2cd799964 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:13:31 +0200 Subject: [PATCH 184/364] Ruby: benign changes to SQLi tests (fixed FNs) --- .../query-tests/security/cwe-089/SqlInjection.expected | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected index 0cc0d213dcc..161cdcc7751 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected @@ -22,6 +22,7 @@ edges | ActiveRecordInjection.rb:70:38:70:50 | ...[...] | ActiveRecordInjection.rb:8:31:8:34 | pass | | ActiveRecordInjection.rb:74:41:74:46 | call to params | ActiveRecordInjection.rb:74:41:74:51 | ...[...] | | ActiveRecordInjection.rb:74:41:74:51 | ...[...] | ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | +| ActiveRecordInjection.rb:79:23:79:28 | call to params | ActiveRecordInjection.rb:79:23:79:35 | ...[...] | | ActiveRecordInjection.rb:83:17:83:22 | call to params | ActiveRecordInjection.rb:83:17:83:31 | ...[...] | | ActiveRecordInjection.rb:84:19:84:24 | call to params | ActiveRecordInjection.rb:84:19:84:33 | ...[...] | | ActiveRecordInjection.rb:88:18:88:23 | call to params | ActiveRecordInjection.rb:88:18:88:35 | ...[...] | @@ -35,6 +36,7 @@ edges | ActiveRecordInjection.rb:103:11:103:17 | ...[...] | ActiveRecordInjection.rb:103:5:103:7 | uid | | ActiveRecordInjection.rb:104:5:104:9 | uidEq | ActiveRecordInjection.rb:108:20:108:32 | ... + ... | | ActiveRecordInjection.rb:141:21:141:26 | call to params | ActiveRecordInjection.rb:141:21:141:44 | ...[...] | +| ActiveRecordInjection.rb:141:21:141:26 | call to params | ActiveRecordInjection.rb:141:21:141:44 | ...[...] | | ActiveRecordInjection.rb:141:21:141:44 | ...[...] | ActiveRecordInjection.rb:20:22:20:30 | condition | | ActiveRecordInjection.rb:155:59:155:64 | call to params | ActiveRecordInjection.rb:155:59:155:74 | ...[...] | | ActiveRecordInjection.rb:155:59:155:74 | ...[...] | ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | @@ -102,6 +104,8 @@ nodes | ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | semmle.label | "id = '#{...}'" | | ActiveRecordInjection.rb:74:41:74:46 | call to params | semmle.label | call to params | | ActiveRecordInjection.rb:74:41:74:51 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:79:23:79:28 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:79:23:79:35 | ...[...] | semmle.label | ...[...] | | ActiveRecordInjection.rb:83:17:83:22 | call to params | semmle.label | call to params | | ActiveRecordInjection.rb:83:17:83:31 | ...[...] | semmle.label | ...[...] | | ActiveRecordInjection.rb:84:19:84:24 | call to params | semmle.label | call to params | @@ -123,6 +127,7 @@ nodes | ActiveRecordInjection.rb:108:20:108:32 | ... + ... | semmle.label | ... + ... | | ActiveRecordInjection.rb:141:21:141:26 | call to params | semmle.label | call to params | | ActiveRecordInjection.rb:141:21:141:44 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:141:21:141:44 | ...[...] | semmle.label | ...[...] | | ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | semmle.label | "this is an unsafe annotation:..." | | ActiveRecordInjection.rb:155:59:155:64 | call to params | semmle.label | call to params | | ActiveRecordInjection.rb:155:59:155:74 | ...[...] | semmle.label | ...[...] | @@ -172,6 +177,7 @@ subpaths | ActiveRecordInjection.rb:61:16:61:21 | <<-SQL | ActiveRecordInjection.rb:62:21:62:26 | call to params | ActiveRecordInjection.rb:61:16:61:21 | <<-SQL | This SQL query depends on a $@. | ActiveRecordInjection.rb:62:21:62:26 | call to params | user-provided value | | ActiveRecordInjection.rb:68:20:68:47 | "user.id = '#{...}'" | ActiveRecordInjection.rb:68:34:68:39 | call to params | ActiveRecordInjection.rb:68:20:68:47 | "user.id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:68:34:68:39 | call to params | user-provided value | | ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | ActiveRecordInjection.rb:74:41:74:46 | call to params | ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:74:41:74:46 | call to params | user-provided value | +| ActiveRecordInjection.rb:79:23:79:35 | ...[...] | ActiveRecordInjection.rb:79:23:79:28 | call to params | ActiveRecordInjection.rb:79:23:79:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:79:23:79:28 | call to params | user-provided value | | ActiveRecordInjection.rb:83:17:83:31 | ...[...] | ActiveRecordInjection.rb:83:17:83:22 | call to params | ActiveRecordInjection.rb:83:17:83:31 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:83:17:83:22 | call to params | user-provided value | | ActiveRecordInjection.rb:84:19:84:33 | ...[...] | ActiveRecordInjection.rb:84:19:84:24 | call to params | ActiveRecordInjection.rb:84:19:84:33 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:84:19:84:24 | call to params | user-provided value | | ActiveRecordInjection.rb:88:18:88:35 | ...[...] | ActiveRecordInjection.rb:88:18:88:23 | call to params | ActiveRecordInjection.rb:88:18:88:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:88:18:88:23 | call to params | user-provided value | @@ -179,6 +185,7 @@ subpaths | ActiveRecordInjection.rb:94:18:94:35 | ...[...] | ActiveRecordInjection.rb:94:18:94:23 | call to params | ActiveRecordInjection.rb:94:18:94:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:94:18:94:23 | call to params | user-provided value | | ActiveRecordInjection.rb:96:23:96:47 | ...[...] | ActiveRecordInjection.rb:96:23:96:28 | call to params | ActiveRecordInjection.rb:96:23:96:47 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:96:23:96:28 | call to params | user-provided value | | ActiveRecordInjection.rb:108:20:108:32 | ... + ... | ActiveRecordInjection.rb:102:10:102:15 | call to params | ActiveRecordInjection.rb:108:20:108:32 | ... + ... | This SQL query depends on a $@. | ActiveRecordInjection.rb:102:10:102:15 | call to params | user-provided value | +| ActiveRecordInjection.rb:141:21:141:44 | ...[...] | ActiveRecordInjection.rb:141:21:141:26 | call to params | ActiveRecordInjection.rb:141:21:141:44 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:141:21:141:26 | call to params | user-provided value | | ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | ActiveRecordInjection.rb:155:59:155:64 | call to params | ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:155:59:155:64 | call to params | user-provided value | | ActiveRecordInjection.rb:168:37:168:41 | query | ActiveRecordInjection.rb:173:5:173:10 | call to params | ActiveRecordInjection.rb:168:37:168:41 | query | This SQL query depends on a $@. | ActiveRecordInjection.rb:173:5:173:10 | call to params | user-provided value | | ActiveRecordInjection.rb:177:43:177:104 | "SELECT * FROM users WHERE id ..." | ActiveRecordInjection.rb:173:5:173:10 | call to params | ActiveRecordInjection.rb:177:43:177:104 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:173:5:173:10 | call to params | user-provided value | @@ -189,4 +196,4 @@ subpaths | PgInjection.rb:20:22:20:25 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:20:22:20:25 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | | PgInjection.rb:21:28:21:31 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:21:28:21:31 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | | PgInjection.rb:32:29:32:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:32:29:32:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | -| PgInjection.rb:44:29:44:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:44:29:44:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | \ No newline at end of file +| PgInjection.rb:44:29:44:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:44:29:44:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | From 8539db07c4c825b9980d79946a1121fdb7996679 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 19 Jun 2023 12:14:48 +0200 Subject: [PATCH 185/364] Ruby: Update ActiveDispatch due to change in toString --- .../action_dispatch/ActionDispatch.expected | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected index 71327350941..4eacd48bd60 100644 --- a/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected @@ -55,12 +55,12 @@ underscore | LotsOfCapitalLetters | lots_of_capital_letters | | invalid | invalid | mimeTypeInstances -| mime_type.rb:2:6:2:28 | Use getMember("Mime").getContent(element_text/html) | -| mime_type.rb:3:6:3:32 | Use getMember("Mime").getMember("Type").getMethod("new").getReturn() | -| mime_type.rb:4:6:4:35 | Use getMember("Mime").getMember("Type").getMethod("lookup").getReturn() | -| mime_type.rb:5:6:5:43 | Use getMember("Mime").getMember("Type").getMethod("lookup_by_extension").getReturn() | -| mime_type.rb:6:6:6:47 | Use getMember("Mime").getMember("Type").getMethod("register").getReturn() | -| mime_type.rb:7:6:7:64 | Use getMember("Mime").getMember("Type").getMethod("register_alias").getReturn() | +| mime_type.rb:2:6:2:28 | ForwardNode(call to fetch) | +| mime_type.rb:3:6:3:32 | ForwardNode(call to new) | +| mime_type.rb:4:6:4:35 | ForwardNode(call to lookup) | +| mime_type.rb:5:6:5:43 | ForwardNode(call to lookup_by_extension) | +| mime_type.rb:6:6:6:47 | ForwardNode(call to register) | +| mime_type.rb:7:6:7:64 | ForwardNode(call to register_alias) | mimeTypeMatchRegExpInterpretations | mime_type.rb:11:11:11:19 | "foo/bar" | | mime_type.rb:12:7:12:15 | "foo/bar" | From 861ac177b828604ad56b3a81b24137e932e918f3 Mon Sep 17 00:00:00 2001 From: Mathew Payne <2772944+GeekMasher@users.noreply.github.com> Date: Mon, 19 Jun 2023 12:03:38 +0100 Subject: [PATCH 186/364] Update csharp/ql/lib/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll Co-authored-by: Jami <57204504+jcogs33@users.noreply.github.com> --- .../code/csharp/security/dataflow/CommandInjectionQuery.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll index 7572d696459..90615faac9f 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/CommandInjectionQuery.qll @@ -67,7 +67,7 @@ module CommandInjection = TaintTracking::Global; /** A source of remote user input. */ class RemoteSource extends Source instanceof RemoteFlowSource { } -/** Command Injection sinks defined through CSV models. */ +/** Command Injection sinks defined through Models as Data. */ private class ExternalCommandInjectionExprSink extends Sink { ExternalCommandInjectionExprSink() { sinkNode(this, "command-injection") } } From 45972105193f78aed9d56a5f279bb2d9ee253b47 Mon Sep 17 00:00:00 2001 From: Mathew Payne <2772944+GeekMasher@users.noreply.github.com> Date: Mon, 19 Jun 2023 12:03:46 +0100 Subject: [PATCH 187/364] Update csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll Co-authored-by: Jami <57204504+jcogs33@users.noreply.github.com> --- csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 22335fb0dce..6805189d2d7 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -214,7 +214,7 @@ module ModelValidation { not kind = [ "code-injection", "command-injection", "file-content-store", "html-injection", - "ldap-injection", "log-injection", "remote", "sql-injection", "url-redirection", + "ldap-injection", "log-injection", "sql-injection", "url-redirection", "js-injection", ] and not kind.matches("encryption-%") and From a6a86acd9a509f26efcec18bf132e603a9640f0d Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Mon, 19 Jun 2023 12:44:01 +0100 Subject: [PATCH 188/364] Fix formatting for ExternalFlow --- csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 6805189d2d7..7a0cc01f7fa 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -214,8 +214,7 @@ module ModelValidation { not kind = [ "code-injection", "command-injection", "file-content-store", "html-injection", - "ldap-injection", "log-injection", "sql-injection", "url-redirection", - "js-injection", + "ldap-injection", "log-injection", "sql-injection", "url-redirection", "js-injection", ] and not kind.matches("encryption-%") and result = "Invalid kind \"" + kind + "\" in sink model." From 00fe8adc092cad90f15ec9eca105fe09f8157e0e Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 19 Jun 2023 15:04:33 +0200 Subject: [PATCH 189/364] Fix name clash --- .../lib/semmle/code/java/security/SensitiveLoggingQuery.qll | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll b/java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll index 984c9f6fcaa..eb40a045c1f 100644 --- a/java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll +++ b/java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll @@ -5,7 +5,6 @@ private import semmle.code.java.dataflow.ExternalFlow import semmle.code.java.dataflow.TaintTracking import semmle.code.java.security.SensitiveActions import semmle.code.java.frameworks.android.Compose -import DataFlow /** A variable that may hold sensitive information, judging by its name. */ class CredentialExpr extends Expr { @@ -45,7 +44,7 @@ deprecated class SensitiveLoggerConfiguration extends TaintTracking::Configurati sanitizer.getType() instanceof TypeType } - override predicate isSanitizerIn(Node node) { this.isSource(node) } + override predicate isSanitizerIn(DataFlow::Node node) { this.isSource(node) } } /** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */ @@ -62,7 +61,7 @@ module SensitiveLoggerConfig implements DataFlow::ConfigSig { sanitizer.getType() instanceof TypeType } - predicate isBarrierIn(Node node) { isSource(node) } + predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } module SensitiveLoggerFlow = TaintTracking::Global; From 3ff71481479774097e13935c19ef4d0ae7975985 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Mon, 19 Jun 2023 15:29:45 +0200 Subject: [PATCH 190/364] Swift: remove `std::result_of` from swift headers `std::result_of` was removed in C++20, though the actual removal from the STL library implementations seems to depend on the version. For example using xcode 14.2 one gets away with a deprecation warning, but xcode 14.3 will fail. As Swift 5.8.1 is still compiled with C++14, we cannot replace `std::result_of` with `std::invoke_result` in the prebuilding patches just yet, but we can do that for the extractor itself, patching the prebuilt package. --- swift/third_party/load.bzl | 2 ++ .../patches/remove-result-of.patch | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 swift/third_party/swift-llvm-support/patches/remove-result-of.patch diff --git a/swift/third_party/load.bzl b/swift/third_party/load.bzl index df21ba1a894..7a3af979577 100644 --- a/swift/third_party/load.bzl +++ b/swift/third_party/load.bzl @@ -39,6 +39,8 @@ def load_dependencies(workspace_name): ), build_file = _build(workspace_name, "swift-llvm-support"), sha256 = sha256, + patch_args = ["-p1"], + patches = ["@%s//swift/third_party/swift-llvm-support:patches/remove-result-of.patch" % workspace_name], ) _github_archive( diff --git a/swift/third_party/swift-llvm-support/patches/remove-result-of.patch b/swift/third_party/swift-llvm-support/patches/remove-result-of.patch new file mode 100644 index 00000000000..ab3f2155b67 --- /dev/null +++ b/swift/third_party/swift-llvm-support/patches/remove-result-of.patch @@ -0,0 +1,30 @@ +`std::result_of` was removed in C++20, but is still used in the Swift headers. We can't +remove it from there before prebuilding, as that is still done with C++14, but we can +replace it with `std::invoke_result` for compiling the extractor. + +diff --git a/include/swift/Basic/RelativePointer.h b/include/swift/Basic/RelativePointer.h +index 73f91262afa..bdaa304c804 100644 +--- a/include/swift/Basic/RelativePointer.h ++++ b/include/swift/Basic/RelativePointer.h +@@ -551,7 +551,7 @@ public: + } + + template +- typename std::result_of::type operator()(ArgTy... arg) const { ++ typename std::invoke_result::type operator()(ArgTy... arg) const { + #if SWIFT_PTRAUTH + void *ptr = this->super::getWithoutCast(); + return reinterpret_cast(ptrauth_sign_unauthenticated( +diff --git a/include/swift/Basic/STLExtras.h b/include/swift/Basic/STLExtras.h +index 7fa3d0c8890..6bc891a9b63 100644 +--- a/include/swift/Basic/STLExtras.h ++++ b/include/swift/Basic/STLExtras.h +@@ -405,7 +405,7 @@ class OptionalTransformIterator { + typename std::iterator_traits::reference; + + using ResultReference = +- typename std::result_of::type; ++ typename std::invoke_result::type; + + public: + /// Used to indicate when the current iterator has already been From 592e7f0b56a312c4f73836f7180e6ca3540cd7de Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Mon, 19 Jun 2023 15:52:16 +0200 Subject: [PATCH 191/364] Swift: add TODO for later swift updates --- swift/third_party/load.bzl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/swift/third_party/load.bzl b/swift/third_party/load.bzl index 7a3af979577..545ac2b4b95 100644 --- a/swift/third_party/load.bzl +++ b/swift/third_party/load.bzl @@ -1,6 +1,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +# TODO: remove `remove-result-of.patch` once we update to a Swift version containing +# https://github.com/apple/swift/commit/2ed2cea2 +# (probably when updating to 5.9) _swift_prebuilt_version = "swift-5.8.1-RELEASE.208" _swift_sha_map = { "Linux-X64": "1d93286d6219e5c5746938ab9287d90efea98039f022cb1433296ccbc1684bc0", From 76e51eeaa2e792beddd753e2d34185d9cf413fa5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:14:14 +0100 Subject: [PATCH 192/364] Swift: Add change note. --- swift/ql/lib/change-notes/2023-06-19-regex-library.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 swift/ql/lib/change-notes/2023-06-19-regex-library.md diff --git a/swift/ql/lib/change-notes/2023-06-19-regex-library.md b/swift/ql/lib/change-notes/2023-06-19-regex-library.md new file mode 100644 index 00000000000..8f3f11725d9 --- /dev/null +++ b/swift/ql/lib/change-notes/2023-06-19-regex-library.md @@ -0,0 +1,6 @@ +--- +category: feature +--- + +* Added new libraries `Regex.qll` and `RegexTreeView.qll` for reasoning about regular expressions +in Swift code and places where they are evaluated. From f90586bc900e429a0743666432094fde5d320403 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Mon, 19 Jun 2023 17:35:26 +0100 Subject: [PATCH 193/364] Bump Swift pack versions --- swift/ql/lib/qlpack.yml | 2 +- swift/ql/src/qlpack.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index f45d347bad3..b2e94cc2667 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-all -version: 0.1.0 +version: 0.1.1-dev groups: swift extractor: swift dbscheme: swift.dbscheme diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml index 2a0bee06578..006dd98fdfb 100644 --- a/swift/ql/src/qlpack.yml +++ b/swift/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-queries -version: 0.1.0 +version: 0.1.1-dev groups: - swift - queries From ead79c98d8408e5c35467dfb288280b8ea25b192 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Mon, 19 Jun 2023 17:35:58 +0100 Subject: [PATCH 194/364] Run `pack release` for Swift packs --- swift/ql/lib/CHANGELOG.md | 13 +++++++++++++ .../change-notes/2023-05-25-dataprotocol-models.md | 4 ---- .../2023-05-25-fix-ast-and-cfg-inconsistencies.md | 5 ----- .../lib/change-notes/2023-05-30-shared-sensitive.md | 4 ---- swift/ql/lib/change-notes/released/0.1.1.md | 13 +++++++++++++ swift/ql/lib/codeql-pack.release.yml | 2 ++ swift/ql/lib/qlpack.yml | 2 +- ...-string-length-conflation-fp.md => CHANGELOG.md} | 7 ++++--- swift/ql/src/change-notes/released/0.1.1.md | 5 +++++ swift/ql/src/codeql-pack.release.yml | 2 ++ swift/ql/src/qlpack.yml | 2 +- 11 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 swift/ql/lib/CHANGELOG.md delete mode 100644 swift/ql/lib/change-notes/2023-05-25-dataprotocol-models.md delete mode 100644 swift/ql/lib/change-notes/2023-05-25-fix-ast-and-cfg-inconsistencies.md delete mode 100644 swift/ql/lib/change-notes/2023-05-30-shared-sensitive.md create mode 100644 swift/ql/lib/change-notes/released/0.1.1.md create mode 100644 swift/ql/lib/codeql-pack.release.yml rename swift/ql/src/{change-notes/2023-05-25-string-length-conflation-fp.md => CHANGELOG.md} (72%) create mode 100644 swift/ql/src/change-notes/released/0.1.1.md create mode 100644 swift/ql/src/codeql-pack.release.yml diff --git a/swift/ql/lib/CHANGELOG.md b/swift/ql/lib/CHANGELOG.md new file mode 100644 index 00000000000..572ca004c63 --- /dev/null +++ b/swift/ql/lib/CHANGELOG.md @@ -0,0 +1,13 @@ +## 0.1.1 + +### Major Analysis Improvements + +* Incorporated the cross-language `SensitiveDataHeuristics.qll` heuristics library into the Swift `SensitiveExprs.qll` library. This adds a number of new heuristics enhancing detection from the library. + +### Minor Analysis Improvements + +* Some models for the `Data` class have been generalized to `DataProtocol` so that they apply more widely. + +### Bug Fixes + +* Fixed a number of inconsistencies in the abstract syntax tree (AST) and in the control-flow graph (CFG). This may lead to more results in queries that use these libraries, or libraries that depend on them (such as dataflow). diff --git a/swift/ql/lib/change-notes/2023-05-25-dataprotocol-models.md b/swift/ql/lib/change-notes/2023-05-25-dataprotocol-models.md deleted file mode 100644 index 6e26484f5dc..00000000000 --- a/swift/ql/lib/change-notes/2023-05-25-dataprotocol-models.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Some models for the `Data` class have been generalized to `DataProtocol` so that they apply more widely. \ No newline at end of file diff --git a/swift/ql/lib/change-notes/2023-05-25-fix-ast-and-cfg-inconsistencies.md b/swift/ql/lib/change-notes/2023-05-25-fix-ast-and-cfg-inconsistencies.md deleted file mode 100644 index 208486b8f27..00000000000 --- a/swift/ql/lib/change-notes/2023-05-25-fix-ast-and-cfg-inconsistencies.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: fix ---- - -* Fixed a number of inconsistencies in the abstract syntax tree (AST) and in the control-flow graph (CFG). This may lead to more results in queries that use these libraries, or libraries that depend on them (such as dataflow). diff --git a/swift/ql/lib/change-notes/2023-05-30-shared-sensitive.md b/swift/ql/lib/change-notes/2023-05-30-shared-sensitive.md deleted file mode 100644 index 03de16f4269..00000000000 --- a/swift/ql/lib/change-notes/2023-05-30-shared-sensitive.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: majorAnalysis ---- -* Incorporated the cross-language `SensitiveDataHeuristics.qll` heuristics library into the Swift `SensitiveExprs.qll` library. This adds a number of new heuristics enhancing detection from the library. \ No newline at end of file diff --git a/swift/ql/lib/change-notes/released/0.1.1.md b/swift/ql/lib/change-notes/released/0.1.1.md new file mode 100644 index 00000000000..572ca004c63 --- /dev/null +++ b/swift/ql/lib/change-notes/released/0.1.1.md @@ -0,0 +1,13 @@ +## 0.1.1 + +### Major Analysis Improvements + +* Incorporated the cross-language `SensitiveDataHeuristics.qll` heuristics library into the Swift `SensitiveExprs.qll` library. This adds a number of new heuristics enhancing detection from the library. + +### Minor Analysis Improvements + +* Some models for the `Data` class have been generalized to `DataProtocol` so that they apply more widely. + +### Bug Fixes + +* Fixed a number of inconsistencies in the abstract syntax tree (AST) and in the control-flow graph (CFG). This may lead to more results in queries that use these libraries, or libraries that depend on them (such as dataflow). diff --git a/swift/ql/lib/codeql-pack.release.yml b/swift/ql/lib/codeql-pack.release.yml new file mode 100644 index 00000000000..92d1505475f --- /dev/null +++ b/swift/ql/lib/codeql-pack.release.yml @@ -0,0 +1,2 @@ +--- +lastReleaseVersion: 0.1.1 diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index b2e94cc2667..5993dfaefcf 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-all -version: 0.1.1-dev +version: 0.1.1 groups: swift extractor: swift dbscheme: swift.dbscheme diff --git a/swift/ql/src/change-notes/2023-05-25-string-length-conflation-fp.md b/swift/ql/src/CHANGELOG.md similarity index 72% rename from swift/ql/src/change-notes/2023-05-25-string-length-conflation-fp.md rename to swift/ql/src/CHANGELOG.md index 7166b5e9ed7..a682b626bb8 100644 --- a/swift/ql/src/change-notes/2023-05-25-string-length-conflation-fp.md +++ b/swift/ql/src/CHANGELOG.md @@ -1,4 +1,5 @@ ---- -category: minorAnalysis ---- +## 0.1.1 + +### Minor Analysis Improvements + * Fixed some false positive results from the `swift/string-length-conflation` query, caused by imprecise sinks. diff --git a/swift/ql/src/change-notes/released/0.1.1.md b/swift/ql/src/change-notes/released/0.1.1.md new file mode 100644 index 00000000000..a682b626bb8 --- /dev/null +++ b/swift/ql/src/change-notes/released/0.1.1.md @@ -0,0 +1,5 @@ +## 0.1.1 + +### Minor Analysis Improvements + +* Fixed some false positive results from the `swift/string-length-conflation` query, caused by imprecise sinks. diff --git a/swift/ql/src/codeql-pack.release.yml b/swift/ql/src/codeql-pack.release.yml new file mode 100644 index 00000000000..92d1505475f --- /dev/null +++ b/swift/ql/src/codeql-pack.release.yml @@ -0,0 +1,2 @@ +--- +lastReleaseVersion: 0.1.1 diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml index 006dd98fdfb..3393d61d8d6 100644 --- a/swift/ql/src/qlpack.yml +++ b/swift/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-queries -version: 0.1.1-dev +version: 0.1.1 groups: - swift - queries From 9f58d961f2e6b8fe1eda91cf795e275783335fa6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:49:27 +0100 Subject: [PATCH 195/364] Swift: Remove TODO about a n unknown failure as it's now diagnosed and planned. --- swift/ql/test/library-tests/regex/redos_variants.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 1788c828bc6..d1ddc1a198c 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -143,7 +143,6 @@ func myRegexpVariantsTests(myUrl: URL) throws { // BAD // attack string: "\n".repeat(100) + "." - // TODO: investigate, we should be getting this one. _ = try Regex(#"(?s)(.|\n)*!"#).firstMatch(in: tainted) // $ hasParseFailure MISSING: redos-vulnerable= // GOOD From eb28266bcb93c065ad252c9c2c4cdffa39176d2b Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:00:52 +0000 Subject: [PATCH 196/364] improv example the help file --- .../CWE-798/HardcodedCredentials.qhelp | 14 ++++++++++++++ .../HardcodedCredentialsHttpRequest.js | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp index 3fd37c3245a..9f6fb3ddfa0 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp @@ -21,6 +21,20 @@

    + +

    + The following code example connects to an HTTP request using an hard-codes authentication header +

    + + + +

    + Instead, user name and password can be supplied through the environment variables + username and password, which can be set externally without hard-coding + credentials in the source code. +

    +
    +

    The following code example connects to a Postgres database using the pg package diff --git a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js new file mode 100644 index 00000000000..5890475085d --- /dev/null +++ b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js @@ -0,0 +1,18 @@ +let base64 = require('base-64'); + +let url = 'http://example.org/auth'; +let username = 'user'; +let password = 'passwd'; + +let headers = new Headers(); + +//headers.append('Content-Type', 'text/json'); +headers.append('Authorization', 'Basic' + base64.encode(username + ":" + password)); + +fetch(url, {method:'GET', + headers: headers, + //credentials: 'user:passwd' + }) +.then(response => response.json()) +.then(json => console.log(json)); +//.done(); From 5fdfd98a1df19ca675d9e7cf7fce79d88e5042f5 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Wed, 14 Jun 2023 17:07:30 +0200 Subject: [PATCH 197/364] delete the deprecated Conatiner::getURL predicates --- cpp/ql/lib/semmle/code/cpp/File.qll | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/File.qll b/cpp/ql/lib/semmle/code/cpp/File.qll index b2e4e0a41a5..bac9b66965e 100644 --- a/cpp/ql/lib/semmle/code/cpp/File.qll +++ b/cpp/ql/lib/semmle/code/cpp/File.qll @@ -34,14 +34,6 @@ class Container extends Locatable, @container { */ string getAbsolutePath() { none() } // overridden by subclasses - /** - * DEPRECATED: Use `getLocation` instead. - * Gets a URL representing the location of this container. - * - * For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls). - */ - deprecated string getURL() { none() } // overridden by subclasses - /** * Gets the relative path of this file or folder from the root folder of the * analyzed source location. The relative path of the root folder itself is @@ -183,12 +175,6 @@ class Folder extends Container, @folder { } override string getAPrimaryQlClass() { result = "Folder" } - - /** - * DEPRECATED: Use `getLocation` instead. - * Gets the URL of this folder. - */ - deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } } /** @@ -213,12 +199,6 @@ class File extends Container, @file { result.hasLocationInfo(_, 0, 0, 0, 0) } - /** - * DEPRECATED: Use `getLocation` instead. - * Gets the URL of this file. - */ - deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } - /** Holds if this file was compiled as C (at any point). */ predicate compiledAsC() { fileannotations(underlyingElement(this), 1, "compiled as c", "1") } From 2104507cec243edda061237744c79c64ec470b0e Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 19 Jun 2023 13:56:41 +0200 Subject: [PATCH 198/364] add change-note --- cpp/ql/lib/change-notes/2023-06-19-delete-container-url.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 cpp/ql/lib/change-notes/2023-06-19-delete-container-url.md diff --git a/cpp/ql/lib/change-notes/2023-06-19-delete-container-url.md b/cpp/ql/lib/change-notes/2023-06-19-delete-container-url.md new file mode 100644 index 00000000000..9fef359a1e8 --- /dev/null +++ b/cpp/ql/lib/change-notes/2023-06-19-delete-container-url.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Deleted the deprecated `getURL` predicate from the `Container`, `Folder`, and `File` classes. Use the `getLocation` predicate instead. \ No newline at end of file From 6da5ec81964b3dd13cc16851c19a3dc09f6bd129 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 20 Jun 2023 00:15:43 +0000 Subject: [PATCH 199/364] Add changed framework coverage reports --- java/documentation/library-coverage/coverage.csv | 2 +- java/documentation/library-coverage/coverage.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index abe364cb2b8..540f282f7c5 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -136,7 +136,7 @@ org.jenkins.ui.icon,,,42,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,41,1 org.jenkins.ui.symbol,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,24,8 org.jooq,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,, org.json,,,236,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,198,38 -org.kohsuke.stapler,3,,343,,,,,,,,,,,,,,,,,1,,,,,,,,,1,,,,1,,,,,,332,11 +org.kohsuke.stapler,20,24,343,,,,,,,2,,,,,,,,,,9,,,,,,,,,4,,,,5,,,,,24,332,11 org.mvel2,16,,,,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,,,,,,,, org.openjdk.jmh.runner.options,1,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,, org.scijava.log,13,,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,, diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index ebcd040ceb8..dcf4eb2704d 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -22,6 +22,6 @@ Java framework & library support Java extensions,"``javax.*``, ``jakarta.*``",63,611,34,2,4,,1,1,2 Kotlin Standard Library,``kotlin*``,,1847,16,14,,,,,2 `Spring `_,``org.springframework.*``,29,483,115,4,,28,14,,35 - Others,"``antlr``, ``cn.hutool.core.codec``, ``com.alibaba.druid.sql``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.influxdb``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``org.yaml.snakeyaml``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",102,4467,554,81,4,18,18,,197 - Totals,,259,12766,2023,278,14,122,33,1,387 + Others,"``antlr``, ``cn.hutool.core.codec``, ``com.alibaba.druid.sql``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.influxdb``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``org.yaml.snakeyaml``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",126,4467,571,89,6,18,18,,200 + Totals,,283,12766,2040,286,16,122,33,1,390 From 6848cba68532446865ef25f6d1d1a19ec3735d65 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Tue, 20 Jun 2023 08:56:58 +0100 Subject: [PATCH 200/364] use more consistent terminology --- .../ql-language-specification.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst index a1b5eb0068d..c4048236251 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -286,8 +286,8 @@ Instantiation-relative and instantiation-nested entities Given an *instantiated module*, every entity has a corresponding entity called the *instantiation-relative* entity, which is determined as follows: -- If the entity is the *underlying module*, its *instantiation-relative entity* is the *instantiated module*. -- If the entity is a parameter of the *underlying module*, its *instantiation-relative entity* is the corresponding argument. +- If the entity is the *underlying module*, its *instantiation-relative* entity is the *instantiated module*. +- If the entity is a parameter of the *underlying module*, its *instantiation-relative* entity is the corresponding argument. - If the entity is declared inside the *underlying module* or its nested modules, its *instantiation-relative* entity is an *instantiation-nested* entity that is generated by the module instantiation. Parameters of any modules that are nested inside the *underlying module* are considered declared inside the module for this purpose. - Otherwise, the entity's *instantiation-relative* entity is the initial entity itself. @@ -318,12 +318,12 @@ Every *completely uninstantiated* entity has a *relevant set of parameters*, whi Note that the *relevant set of parameters* by construction contains only *completely uninstantiated* parameters. -For a *completely uninstantiated* parameter, the *bottom-up instantiation-resolved* parameter relative to an entity is defined as: +For a *completely uninstantiated* parameter, the *bottom-up instantiation-resolution* relative to an entity is defined as: -- If the entity is an *instantiated module* or an *instantiation-nested* entity, the *bottom-up instantiation-resolved* parameter is the *instantiation-relative* parameter of the *bottom-up instantiation-resolved* parameter relative to the *underlying module*. -- Otherwise, the *bottom-up instantiation-resolved* parameter is the parameter itself. +- If the entity is an *instantiated module* or an *instantiation-nested* entity, the *bottom-up instantiation-resolution* is the *instantiation-relative* entity of the *bottom-up instantiation-resolution* relative to the *underlying module*. +- Otherwise, the *bottom-up instantiation-resolution* is the parameter itself. -Two *instantiated modules* or two *instantiation-nested* entities are considered *equivalent* if they have the same *underlying completely uninstantiated* entity and each parameter in its *relevant set of parameters* has the same *bottom-up instantiation-resolved* parameter relative to either *instantiated module*. +Two *instantiated modules* or two *instantiation-nested* entities are considered *equivalent* if they have the same *underlying completely uninstantiated* entity and each parameter in its *relevant set of parameters* has the same *bottom-up instantiation-resolution* relative to either *instantiated module*. Module instantiation is applicative, meaning that *equivalent* *instantiated modules* and *equivalent* *instantiation-nested* entities are indistinguishable. From 0c4eb6892163c43f576083b71bdfb5cd3b48b6bd Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Tue, 20 Jun 2023 08:59:18 +0100 Subject: [PATCH 201/364] introduce concept of fully instantiated entity --- .../ql-language-reference/ql-language-specification.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst index c4048236251..32244023c21 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -323,6 +323,8 @@ For a *completely uninstantiated* parameter, the *bottom-up instantiation-resolu - If the entity is an *instantiated module* or an *instantiation-nested* entity, the *bottom-up instantiation-resolution* is the *instantiation-relative* entity of the *bottom-up instantiation-resolution* relative to the *underlying module*. - Otherwise, the *bottom-up instantiation-resolution* is the parameter itself. +An entity is called *fully instantiated* if none of the *bottom-up instantiation-resolutions* of the parameters in the *relevant set of parameters* of the entity's *underlying completely uninstantiated* entity are parameters. + Two *instantiated modules* or two *instantiation-nested* entities are considered *equivalent* if they have the same *underlying completely uninstantiated* entity and each parameter in its *relevant set of parameters* has the same *bottom-up instantiation-resolution* relative to either *instantiated module*. Module instantiation is applicative, meaning that *equivalent* *instantiated modules* and *equivalent* *instantiation-nested* entities are indistinguishable. @@ -2040,7 +2042,7 @@ Stratification A QL program can be *stratified* to a sequence of *layers*. A layer is a set of predicates and types. -A valid stratification must include each predicate and type in the QL program. It must not include any other predicates or types. +A valid stratification must include each predicate and type in the QL program that is *fully instantiated*. It must not include any other predicates or types. A valid stratification must not include the same predicate in multiple layers. From 890a67d2eef1e700e2967015d5b824c5265831ea Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 15 Jun 2023 16:44:29 +0200 Subject: [PATCH 202/364] Introduce modules to merge 3, 4, and 5 inline expectation tests --- .../util/test/InlineExpectationsTest.qll | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/shared/util/codeql/util/test/InlineExpectationsTest.qll b/shared/util/codeql/util/test/InlineExpectationsTest.qll index 7d3806cb4b5..83c6a851f7d 100644 --- a/shared/util/codeql/util/test/InlineExpectationsTest.qll +++ b/shared/util/codeql/util/test/InlineExpectationsTest.qll @@ -396,6 +396,63 @@ module Make { } } + /** + * A module that merges three test signatures. + */ + module MergeTests3 implements TestSig { + private module M = MergeTests, TestImpl3>; + + string getARelevantTag() { result = M::getARelevantTag() } + + predicate hasActualResult(Impl::Location location, string element, string tag, string value) { + M::hasActualResult(location, element, tag, value) + } + + predicate hasOptionalResult(Impl::Location location, string element, string tag, string value) { + M::hasOptionalResult(location, element, tag, value) + } + } + + /** + * A module that merges four test signatures. + */ + module MergeTests4 + implements TestSig + { + private module M = MergeTests, TestImpl4>; + + string getARelevantTag() { result = M::getARelevantTag() } + + predicate hasActualResult(Impl::Location location, string element, string tag, string value) { + M::hasActualResult(location, element, tag, value) + } + + predicate hasOptionalResult(Impl::Location location, string element, string tag, string value) { + M::hasOptionalResult(location, element, tag, value) + } + } + + /** + * A module that merges five test signatures. + */ + module MergeTests5< + TestSig TestImpl1, TestSig TestImpl2, TestSig TestImpl3, TestSig TestImpl4, TestSig TestImpl5> + implements TestSig + { + private module M = + MergeTests, TestImpl5>; + + string getARelevantTag() { result = M::getARelevantTag() } + + predicate hasActualResult(Impl::Location location, string element, string tag, string value) { + M::hasActualResult(location, element, tag, value) + } + + predicate hasOptionalResult(Impl::Location location, string element, string tag, string value) { + M::hasOptionalResult(location, element, tag, value) + } + } + private module LegacyImpl implements TestSig { string getARelevantTag() { result = any(InlineExpectationsTest t).getARelevantTag() } From d6d21e3928d501ca623ea93bb29c726e676460b5 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 15 Jun 2023 16:43:48 +0200 Subject: [PATCH 203/364] Go: Update remaining inline expectation tests to use the paramterized module --- .../frameworks/ElazarlGoproxy/test.expected | 2 + .../go/frameworks/ElazarlGoproxy/test.ql | 46 ++++++-------- .../go/frameworks/SQL/QueryString.expected | 2 + .../semmle/go/frameworks/SQL/QueryString.ql | 38 +++++------ .../semmle/go/frameworks/Yaml/tests.expected | 2 + .../semmle/go/frameworks/Yaml/tests.ql | 63 +++++++++---------- 6 files changed, 72 insertions(+), 81 deletions(-) diff --git a/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.expected b/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.expected index e69de29bb2d..48de9172b36 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.ql b/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.ql index e8c68c1c3e1..2ffca8a692a 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.ql +++ b/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.ql @@ -1,12 +1,10 @@ import go import TestUtilities.InlineExpectationsTest -class UntrustedFlowSourceTest extends InlineExpectationsTest { - UntrustedFlowSourceTest() { this = "untrustedflowsource" } +module UntrustedFlowSourceTest implements TestSig { + string getARelevantTag() { result = "untrustedflowsource" } - override string getARelevantTag() { result = "untrustedflowsource" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { tag = "untrustedflowsource" and value = element and exists(UntrustedFlowSource src | value = "\"" + src.toString() + "\"" | @@ -16,12 +14,10 @@ class UntrustedFlowSourceTest extends InlineExpectationsTest { } } -class HeaderWriteTest extends InlineExpectationsTest { - HeaderWriteTest() { this = "headerwrite" } +module HeaderWriteTest implements TestSig { + string getARelevantTag() { result = "headerwrite" } - override string getARelevantTag() { result = "headerwrite" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { tag = "headerwrite" and exists(Http::HeaderWrite hw, string name, string val | element = hw.toString() | hw.definesHeader(name, val) and @@ -32,12 +28,10 @@ class HeaderWriteTest extends InlineExpectationsTest { } } -class LoggerTest extends InlineExpectationsTest { - LoggerTest() { this = "LoggerTest" } +module LoggerTest implements TestSig { + string getARelevantTag() { result = "logger" } - override string getARelevantTag() { result = "logger" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(LoggerCall log | log.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and @@ -48,32 +42,32 @@ class LoggerTest extends InlineExpectationsTest { } } -class Config extends TaintTracking::Configuration { - Config() { this = "goproxy config" } - - override predicate isSource(DataFlow::Node n) { +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { n = any(DataFlow::CallNode c | c.getCalleeName().matches("tainted%")).getResult() } - override predicate isSink(DataFlow::Node n) { + predicate isSink(DataFlow::Node n) { n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument() } } -class TaintFlow extends InlineExpectationsTest { - TaintFlow() { this = "goproxy flow" } +module Flow = TaintTracking::Global; - override string getARelevantTag() { result = "taintflow" } +module TaintFlow implements TestSig { + string getARelevantTag() { result = "taintflow" } - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { tag = "taintflow" and value = "" and element = "" and - exists(Config c, DataFlow::Node toNode | + exists(DataFlow::Node toNode | toNode .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and - c.hasFlowTo(toNode) + Flow::flowTo(toNode) ) } } + +import MakeTest> diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.expected index e69de29bb2d..48de9172b36 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.ql index 31852f1b862..6b1c1f70e04 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.ql +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.ql @@ -1,12 +1,10 @@ import go import TestUtilities.InlineExpectationsTest -class SqlTest extends InlineExpectationsTest { - SqlTest() { this = "SQLTest" } +module SqlTest implements TestSig { + string getARelevantTag() { result = "query" } - override string getARelevantTag() { result = "query" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { tag = "query" and exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() | q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), @@ -17,12 +15,10 @@ class SqlTest extends InlineExpectationsTest { } } -class QueryString extends InlineExpectationsTest { - QueryString() { this = "QueryString no Query" } +module QueryString implements TestSig { + string getARelevantTag() { result = "querystring" } - override string getARelevantTag() { result = "querystring" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { tag = "querystring" and element = "" and exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) | @@ -33,30 +29,30 @@ class QueryString extends InlineExpectationsTest { } } -class Config extends TaintTracking::Configuration { - Config() { this = "pg-orm config" } +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit } - override predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit } - - override predicate isSink(DataFlow::Node n) { + predicate isSink(DataFlow::Node n) { n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument() } } -class TaintFlow extends InlineExpectationsTest { - TaintFlow() { this = "pg-orm flow" } +module Flow = TaintTracking::Global; - override string getARelevantTag() { result = "flowfrom" } +module TaintFlow implements TestSig { + string getARelevantTag() { result = "flowfrom" } - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { tag = "flowfrom" and element = "" and - exists(Config c, DataFlow::Node fromNode, DataFlow::Node toNode | + exists(DataFlow::Node fromNode, DataFlow::Node toNode | toNode .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and - c.hasFlow(fromNode, toNode) and + Flow::flow(fromNode, toNode) and value = fromNode.asExpr().(StringLit).getValue() ) } } + +import MakeTest> diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.expected b/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.expected index e69de29bb2d..48de9172b36 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.ql b/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.ql index 273f031fc32..c4c0cafb50e 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.ql +++ b/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.ql @@ -11,32 +11,29 @@ DataFlow::CallNode getAYamlCall() { isYamlFunction(result.getACalleeIncludingExternals().asFunction()) } -class TaintTransitsFunctionConfig extends TaintTracking::Configuration { - TaintTransitsFunctionConfig() { this = "TaintTransitsFunctionConfig" } - - predicate isSourceSinkPair(DataFlow::Node inNode, DataFlow::Node outNode) { - exists(DataFlow::CallNode cn | cn = getAYamlCall() | - inNode = [cn.getAnArgument(), cn.getReceiver()] and - ( - outNode.(DataFlow::PostUpdateNode).getPreUpdateNode() = - [cn.getAnArgument(), cn.getReceiver()] - or - outNode = cn.getAResult() - ) +predicate isSourceSinkPair(DataFlow::Node inNode, DataFlow::Node outNode) { + exists(DataFlow::CallNode cn | cn = getAYamlCall() | + inNode = [cn.getAnArgument(), cn.getReceiver()] and + ( + outNode.(DataFlow::PostUpdateNode).getPreUpdateNode() = [cn.getAnArgument(), cn.getReceiver()] + or + outNode = cn.getAResult() ) - } - - override predicate isSource(DataFlow::Node n) { this.isSourceSinkPair(n, _) } - - override predicate isSink(DataFlow::Node n) { this.isSourceSinkPair(_, n) } + ) } -class TaintFunctionModelTest extends InlineExpectationsTest { - TaintFunctionModelTest() { this = "TaintFunctionModelTest" } +module TaintTransitsFunctionConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { isSourceSinkPair(n, _) } - override string getARelevantTag() { result = "ttfnmodelstep" } + predicate isSink(DataFlow::Node n) { isSourceSinkPair(_, n) } +} - override predicate hasActualResult(Location location, string element, string tag, string value) { +module TaintTransitsFunctionFlow = TaintTracking::Global; + +module TaintFunctionModelTest implements TestSig { + string getARelevantTag() { result = "ttfnmodelstep" } + + predicate hasActualResult(Location location, string element, string tag, string value) { tag = "ttfnmodelstep" and ( exists(TaintTracking::FunctionModel model, DataFlow::CallNode call | call = model.getACall() | @@ -46,9 +43,9 @@ class TaintFunctionModelTest extends InlineExpectationsTest { value = "\"" + model.getAnInputNode(call) + " -> " + model.getAnOutputNode(call) + "\"" ) or - exists(TaintTransitsFunctionConfig config, DataFlow::Node arg, DataFlow::Node output | - config.hasFlow(arg, output) and - config.isSourceSinkPair(arg, output) and + exists(DataFlow::Node arg, DataFlow::Node output | + TaintTransitsFunctionFlow::flow(arg, output) and + isSourceSinkPair(arg, output) and arg.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and element = arg.toString() and @@ -58,12 +55,10 @@ class TaintFunctionModelTest extends InlineExpectationsTest { } } -class MarshalerTest extends InlineExpectationsTest { - MarshalerTest() { this = "MarshalerTest" } +module MarshalerTest implements TestSig { + string getARelevantTag() { result = "marshaler" } - override string getARelevantTag() { result = "marshaler" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { tag = "marshaler" and exists(MarshalingFunction m, DataFlow::CallNode call | call = m.getACall() | call.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), @@ -76,12 +71,10 @@ class MarshalerTest extends InlineExpectationsTest { } } -class UnmarshalerTest extends InlineExpectationsTest { - UnmarshalerTest() { this = "UnmarshalerTest" } +module UnmarshalerTest implements TestSig { + string getARelevantTag() { result = "unmarshaler" } - override string getARelevantTag() { result = "unmarshaler" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { tag = "unmarshaler" and exists(UnmarshalingFunction m, DataFlow::CallNode call | call = m.getACall() | call.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), @@ -93,3 +86,5 @@ class UnmarshalerTest extends InlineExpectationsTest { ) } } + +import MakeTest> From c53e529bac89562ad6222f16a69d45e21a7913fa Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 15 Jun 2023 16:44:19 +0200 Subject: [PATCH 204/364] Ruby: Update remaining inline expectation tests to use the paramterized module --- .../test/TestUtilities/InlineTypeTrackingFlowTest.qll | 10 +++++----- .../array-flow/type-tracking-array-flow.expected | 2 ++ .../dataflow/global/TypeTrackingInlineTest.expected | 2 ++ .../hash-flow/type-tracking-hash-flow.expected | 2 ++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ruby/ql/test/TestUtilities/InlineTypeTrackingFlowTest.qll b/ruby/ql/test/TestUtilities/InlineTypeTrackingFlowTest.qll index 2e60d1ce0e8..6d584ef31dc 100644 --- a/ruby/ql/test/TestUtilities/InlineTypeTrackingFlowTest.qll +++ b/ruby/ql/test/TestUtilities/InlineTypeTrackingFlowTest.qll @@ -15,12 +15,10 @@ DataFlow::LocalSourceNode track(DataFlow::CallNode source) { result = track(TypeTracker::end(), source) } -class TypeTrackingFlowTest extends InlineExpectationsTest { - TypeTrackingFlowTest() { this = "TypeTrackingFlowTest" } +module TypeTrackingFlowTest implements TestSig { + string getARelevantTag() { result = "hasValueFlow" } - override string getARelevantTag() { result = "hasValueFlow" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node sink, DataFlow::Node source | defaultSink(sink) and track(source).flowsTo(sink) and @@ -31,3 +29,5 @@ class TypeTrackingFlowTest extends InlineExpectationsTest { ) } } + +import MakeTest diff --git a/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected b/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected index 83e81729d98..5374f468c3e 100644 --- a/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected @@ -1,3 +1,5 @@ +failures +testFailures | array_flow.rb:107:10:107:13 | ...[...] | Unexpected result: hasValueFlow=11.2 | | array_flow.rb:179:28:179:46 | # $ hasValueFlow=19 | Missing result:hasValueFlow=19 | | array_flow.rb:180:28:180:46 | # $ hasValueFlow=19 | Missing result:hasValueFlow=19 | diff --git a/ruby/ql/test/library-tests/dataflow/global/TypeTrackingInlineTest.expected b/ruby/ql/test/library-tests/dataflow/global/TypeTrackingInlineTest.expected index 88d69578cf7..8fbd6f51044 100644 --- a/ruby/ql/test/library-tests/dataflow/global/TypeTrackingInlineTest.expected +++ b/ruby/ql/test/library-tests/dataflow/global/TypeTrackingInlineTest.expected @@ -1,3 +1,5 @@ +failures +testFailures | captured_variables.rb:9:14:9:14 | x | Fixed missing result:hasValueFlow=1.2 | | captured_variables.rb:16:14:16:14 | x | Fixed missing result:hasValueFlow=1.3 | | instance_variables.rb:20:16:20:33 | # $ hasValueFlow=7 | Missing result:hasValueFlow=7 | diff --git a/ruby/ql/test/library-tests/dataflow/hash-flow/type-tracking-hash-flow.expected b/ruby/ql/test/library-tests/dataflow/hash-flow/type-tracking-hash-flow.expected index ff6899d41c2..af062eec4fd 100644 --- a/ruby/ql/test/library-tests/dataflow/hash-flow/type-tracking-hash-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/hash-flow/type-tracking-hash-flow.expected @@ -1,3 +1,5 @@ +failures +testFailures | hash_flow.rb:65:21:65:40 | # $ hasValueFlow=3.3 | Missing result:hasValueFlow=3.3 | | hash_flow.rb:66:21:66:49 | # $ SPURIOUS hasValueFlow=3.3 | Missing result:hasValueFlow=3.3 | | hash_flow.rb:114:10:114:17 | ...[...] | Unexpected result: hasValueFlow=7.2 | From dba44605264630d3a52fd2d0b21f15c6a9daa757 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 15 Jun 2023 16:44:04 +0200 Subject: [PATCH 205/364] Python: Update more inline expectation tests to use the paramterized module --- .../dataflow/TestUtil/DataflowQueryTest.qll | 16 +- .../dataflow/TestUtil/FlowTest.qll | 29 ++- .../dataflow/TestUtil/LocalFlowStepTest.qll | 10 +- .../dataflow/TestUtil/MaximalFlowTest.qll | 22 +- .../dataflow/TestUtil/NormalDataflowTest.qll | 18 +- .../TestUtil/NormalTaintTrackingTest.qll | 16 +- .../dataflow/TestUtil/UnresolvedCalls.qll | 36 ++-- .../dataflow/basic/localFlowStepTest.expected | 2 + .../dataflow/basic/maximalFlowTest.expected | 2 + .../coverage/NormalDataflowTest.expected | 1 + .../exceptions/NormalDataflowTest.expected | 1 + .../fieldflow/NormalDataflowTest.expected | 1 + .../fieldflow/UnresolvedCalls.expected | 2 + .../dataflow/fieldflow/UnresolvedCalls.ql | 8 +- .../match/NormalDataflowTest.expected | 1 + .../module-initialization/localFlow.expected | 2 + .../module-initialization/localFlow.ql | 18 +- .../dataflow/regression/dataflow.ql | 2 +- .../NormalTaintTrackingTest.expected | 1 + .../dataflow/summaries/summaries.ql | 6 +- .../commonSanitizer/InlineTaintTest.expected | 3 +- .../commonSanitizer/InlineTaintTest.ql | 10 +- .../customSanitizer/InlineTaintTest.expected | 45 ++-- .../customSanitizer/InlineTaintTest.ql | 14 +- .../InlineTaintTest.expected | 3 +- .../InlineTaintTest.ql | 1 + .../InlineTaintTest.expected | 3 +- .../InlineTaintTest.ql | 1 + .../generator-flow/InlineTaintTest.expected | 3 +- .../generator-flow/InlineTaintTest.ql | 1 + .../NormalDataflowTest.expected | 1 + .../InlineTaintTest.expected | 3 +- .../unwanted-global-flow/InlineTaintTest.ql | 1 + .../test/experimental/dataflow/testConfig.qll | 12 +- .../experimental/dataflow/testTaintConfig.qll | 12 +- .../dataflow/typetracking/tracked.expected | 2 + .../dataflow/typetracking/tracked.ql | 42 ++-- .../typetracking_imports/tracked.expected | 2 + .../dataflow/variable-capture/CaptureTest.ql | 2 +- .../test/experimental/meta/ConceptsTest.qll | 203 +++++++----------- .../experimental/meta/InlineTaintTest.qll | 90 ++++---- python/ql/test/experimental/meta/MaDTest.qll | 18 +- .../meta/debug/InlineTaintTestPaths.ql | 6 +- .../meta/debug/dataflowTestPaths.ql | 4 +- .../InlineTaintTest.expected | 3 +- .../inline-taint-test-demo/InlineTaintTest.ql | 1 + .../DataflowQueryTest.expected | 1 + .../frameworks/aioch/ConceptsTest.expected | 2 + .../frameworks/aiohttp/ConceptsTest.expected | 2 + .../aiohttp/InlineTaintTest.expected | 3 +- .../frameworks/aiohttp/InlineTaintTest.ql | 1 + .../frameworks/aiomysql/ConceptsTest.expected | 2 + .../frameworks/aiopg/ConceptsTest.expected | 2 + .../aiosqlite/ConceptsTest.expected | 2 + .../frameworks/asyncpg/ConceptsTest.expected | 2 + .../frameworks/asyncpg/MaDTest.expected | 2 + .../cassandra-driver/ConceptsTest.expected | 2 + .../clickhouse_driver/ConceptsTest.expected | 2 + .../frameworks/crypto/ConceptsTest.expected | 2 + .../cryptodome/ConceptsTest.expected | 2 + .../cryptography/ConceptsTest.expected | 2 + .../cx_Oracle/ConceptsTest.expected | 2 + .../frameworks/dill/ConceptsTest.expected | 2 + .../django-orm/NormalDataflowTest.expected | 1 + .../django-v1/ConceptsTest.expected | 2 + .../django-v2-v3/ConceptsTest.expected | 2 + .../django-v2-v3/InlineTaintTest.expected | 3 +- .../django-v2-v3/InlineTaintTest.ql | 1 + .../frameworks/django/ConceptsTest.expected | 2 + .../frameworks/fabric/ConceptsTest.expected | 2 + .../fabric/InlineTaintTest.expected | 3 +- .../frameworks/fabric/InlineTaintTest.ql | 1 + .../frameworks/fastapi/ConceptsTest.expected | 2 + .../fastapi/InlineTaintTest.expected | 3 +- .../frameworks/fastapi/InlineTaintTest.ql | 1 + .../frameworks/flask/ConceptsTest.expected | 2 + .../frameworks/flask/InlineTaintTest.expected | 3 +- .../frameworks/flask/InlineTaintTest.ql | 1 + .../flask_admin/ConceptsTest.expected | 2 + .../flask_admin/InlineTaintTest.expected | 3 +- .../frameworks/flask_admin/InlineTaintTest.ql | 1 + .../flask_sqlalchemy/ConceptsTest.expected | 2 + .../flask_sqlalchemy/InlineTaintTest.expected | 3 +- .../flask_sqlalchemy/InlineTaintTest.ql | 1 + .../frameworks/httpx/ConceptsTest.expected | 2 + .../frameworks/idna/ConceptsTest.expected | 2 + .../frameworks/idna/InlineTaintTest.expected | 3 +- .../frameworks/idna/InlineTaintTest.ql | 1 + .../frameworks/invoke/ConceptsTest.expected | 2 + .../frameworks/jmespath/ConceptsTest.expected | 2 + .../jmespath/InlineTaintTest.expected | 3 +- .../frameworks/jmespath/InlineTaintTest.ql | 1 + .../frameworks/libtaxii/ConceptsTest.expected | 2 + .../frameworks/lxml/ConceptsTest.expected | 2 + .../markupsafe/ConceptsTest.expected | 2 + .../markupsafe/InlineTaintTest.expected | 3 +- .../frameworks/markupsafe/InlineTaintTest.ql | 10 +- .../multidict/ConceptsTest.expected | 2 + .../multidict/InlineTaintTest.expected | 3 +- .../frameworks/multidict/InlineTaintTest.ql | 1 + .../ConceptsTest.expected | 2 + .../frameworks/mysqldb/ConceptsTest.expected | 2 + .../frameworks/oracledb/ConceptsTest.expected | 2 + .../frameworks/peewee/ConceptsTest.expected | 2 + .../peewee/InlineTaintTest.expected | 3 +- .../frameworks/peewee/InlineTaintTest.ql | 1 + .../phoenixdb/ConceptsTest.expected | 2 + .../frameworks/pycurl/ConceptsTest.expected | 2 + .../frameworks/pymssql/ConceptsTest.expected | 2 + .../frameworks/pymysql/ConceptsTest.expected | 2 + .../frameworks/pyodbc/ConceptsTest.expected | 2 + .../frameworks/requests/ConceptsTest.expected | 2 + .../requests/InlineTaintTest.expected | 3 +- .../frameworks/requests/InlineTaintTest.ql | 1 + .../rest_framework/ConceptsTest.expected | 2 + .../rest_framework/InlineTaintTest.expected | 3 +- .../rest_framework/InlineTaintTest.ql | 1 + .../frameworks/rsa/ConceptsTest.expected | 2 + .../frameworks/rsa/InlineTaintTest.expected | 3 +- .../frameworks/rsa/InlineTaintTest.ql | 1 + .../ruamel.yaml/ConceptsTest.expected | 2 + .../simplejson/ConceptsTest.expected | 2 + .../simplejson/InlineTaintTest.expected | 3 +- .../frameworks/simplejson/InlineTaintTest.ql | 1 + .../sqlalchemy/ConceptsTest.expected | 2 + .../sqlalchemy/InlineTaintTest.expected | 3 +- .../frameworks/sqlalchemy/InlineTaintTest.ql | 1 + .../stdlib-py2/ConceptsTest.expected | 2 + .../stdlib-py3/ConceptsTest.expected | 2 + .../frameworks/stdlib/ConceptsTest.expected | 2 + .../stdlib/InlineTaintTest.expected | 3 +- .../frameworks/stdlib/InlineTaintTest.ql | 1 + .../frameworks/toml/ConceptsTest.expected | 2 + .../frameworks/tornado/ConceptsTest.expected | 2 + .../tornado/InlineTaintTest.expected | 3 +- .../frameworks/tornado/InlineTaintTest.ql | 1 + .../frameworks/twisted/ConceptsTest.expected | 2 + .../twisted/InlineTaintTest.expected | 3 +- .../frameworks/twisted/InlineTaintTest.ql | 1 + .../frameworks/ujson/ConceptsTest.expected | 2 + .../frameworks/ujson/InlineTaintTest.expected | 3 +- .../frameworks/ujson/InlineTaintTest.ql | 1 + .../frameworks/urllib3/ConceptsTest.expected | 2 + .../xmltodict/ConceptsTest.expected | 2 + .../frameworks/yaml/ConceptsTest.expected | 2 + .../frameworks/yarl/ConceptsTest.expected | 2 + .../frameworks/yarl/InlineTaintTest.expected | 3 +- .../frameworks/yarl/InlineTaintTest.ql | 1 + .../regex/SubstructureTests.expected | 2 + .../library-tests/regex/SubstructureTests.ql | 34 ++- .../DataflowQueryTest.expected | 1 + .../DataflowQueryTest.expected | 1 + .../DataflowQueryTest.expected | 1 + 153 files changed, 551 insertions(+), 379 deletions(-) diff --git a/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll b/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll index 1c9259038bc..74a43bb4cc4 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll @@ -3,12 +3,10 @@ import semmle.python.dataflow.new.DataFlow import TestUtilities.InlineExpectationsTest private import semmle.python.dataflow.new.internal.PrintNode -class DataFlowQueryTest extends InlineExpectationsTest { - DataFlowQueryTest() { this = "DataFlowQueryTest" } +module DataFlowQueryTest implements TestSig { + string getARelevantTag() { result = "result" } - override string getARelevantTag() { result = "result" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Configuration cfg, DataFlow::Node sink | cfg.hasFlowTo(sink) | location = sink.getLocation() and tag = "result" and @@ -22,7 +20,7 @@ class DataFlowQueryTest extends InlineExpectationsTest { // Sometimes a line contains both an alert and a safe sink. // In this situation, the annotation form `OK(safe sink)` // can be useful. - override predicate hasOptionalResult(Location location, string element, string tag, string value) { + predicate hasOptionalResult(Location location, string element, string tag, string value) { exists(DataFlow::Configuration cfg, DataFlow::Node sink | cfg.isSink(sink) or cfg.isSink(sink, _) | @@ -34,6 +32,8 @@ class DataFlowQueryTest extends InlineExpectationsTest { } } +import MakeTest + query predicate missingAnnotationOnSink(Location location, string error, string element) { error = "ERROR, you should add `# $ MISSING: result=BAD` or `result=OK` annotation" and exists(DataFlow::Node sink | @@ -42,13 +42,13 @@ query predicate missingAnnotationOnSink(Location location, string error, string location = sink.getLocation() and element = prettyExpr(sink.asExpr()) and not exists(DataFlow::Configuration cfg | cfg.hasFlowTo(sink)) and - not exists(FalseNegativeExpectation missingResult | + not exists(FalseNegativeTestExpectation missingResult | missingResult.getTag() = "result" and missingResult.getValue() = "BAD" and missingResult.getLocation().getFile() = location.getFile() and missingResult.getLocation().getStartLine() = location.getStartLine() ) and - not exists(GoodExpectation okResult | + not exists(GoodTestExpectation okResult | okResult.getTag() = "result" and okResult.getValue() in ["OK", "OK(" + prettyNode(sink) + ")"] and okResult.getLocation().getFile() = location.getFile() and diff --git a/python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll b/python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll index 2f5d7de5952..e6abf741b36 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/FlowTest.qll @@ -3,22 +3,21 @@ import semmle.python.dataflow.new.DataFlow import TestUtilities.InlineExpectationsTest private import semmle.python.dataflow.new.internal.PrintNode -abstract class FlowTest extends InlineExpectationsTest { - bindingset[this] - FlowTest() { any() } +signature module FlowTestSig { + string flowTag(); - abstract string flowTag(); + predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode); +} - abstract predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode); +private module FlowTest implements TestSig { + string getARelevantTag() { result = Impl::flowTag() } - override string getARelevantTag() { result = this.flowTag() } - - override predicate hasActualResult(Location location, string element, string tag, string value) { - exists(DataFlow::Node fromNode, DataFlow::Node toNode | this.relevantFlow(fromNode, toNode) | + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(DataFlow::Node fromNode, DataFlow::Node toNode | Impl::relevantFlow(fromNode, toNode) | location = toNode.getLocation() and - tag = this.flowTag() and + tag = Impl::flowTag() and value = - "\"" + prettyNode(fromNode).replaceAll("\"", "'") + this.lineStr(fromNode, toNode) + " -> " + + "\"" + prettyNode(fromNode).replaceAll("\"", "'") + lineStr(fromNode, toNode) + " -> " + prettyNode(toNode).replaceAll("\"", "'") + "\"" and element = toNode.toString() ) @@ -38,3 +37,11 @@ abstract class FlowTest extends InlineExpectationsTest { ) } } + +module MakeFlowTest { + import MakeTest> +} + +module MakeFlowTest2 { + import MakeTest, FlowTest>> +} diff --git a/python/ql/test/experimental/dataflow/TestUtil/LocalFlowStepTest.qll b/python/ql/test/experimental/dataflow/TestUtil/LocalFlowStepTest.qll index c2c180627ec..6cbfe917fd4 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/LocalFlowStepTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/LocalFlowStepTest.qll @@ -2,12 +2,12 @@ import python import semmle.python.dataflow.new.DataFlow import FlowTest -class LocalFlowStepTest extends FlowTest { - LocalFlowStepTest() { this = "LocalFlowStepTest" } +module LocalFlowStepTest implements FlowTestSig { + string flowTag() { result = "step" } - override string flowTag() { result = "step" } - - override predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode) { + predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode) { DataFlow::localFlowStep(fromNode, toNode) } } + +import MakeFlowTest diff --git a/python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll b/python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll index 6615afb9247..681e51ca604 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/MaximalFlowTest.qll @@ -3,25 +3,23 @@ import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.DataFlowPrivate import FlowTest -class MaximalFlowTest extends FlowTest { - MaximalFlowTest() { this = "MaximalFlowTest" } +module MaximalFlowTest implements FlowTestSig { + string flowTag() { result = "flow" } - override string flowTag() { result = "flow" } - - override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { source != sink and - exists(MaximalFlowsConfig cfg | cfg.hasFlow(source, sink)) + MaximalFlows::flow(source, sink) } } +import MakeFlowTest + /** * A configuration to find all "maximal" flows. * To be used on small programs. */ -class MaximalFlowsConfig extends DataFlow::Configuration { - MaximalFlowsConfig() { this = "MaximalFlowsConfig" } - - override predicate isSource(DataFlow::Node node) { +module MaximalFlowsConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { exists(node.getLocation().getFile().getRelativePath()) and not node.asCfgNode() instanceof CallNode and not node.asCfgNode().getNode() instanceof Return and @@ -32,7 +30,7 @@ class MaximalFlowsConfig extends DataFlow::Configuration { not DataFlow::localFlowStep(_, node) } - override predicate isSink(DataFlow::Node node) { + predicate isSink(DataFlow::Node node) { exists(node.getLocation().getFile().getRelativePath()) and not any(CallNode c).getArg(_) = node.asCfgNode() and not node instanceof DataFlow::ArgumentNode and @@ -40,3 +38,5 @@ class MaximalFlowsConfig extends DataFlow::Configuration { not DataFlow::localFlowStep(node, _) } } + +module MaximalFlows = DataFlow::Global; diff --git a/python/ql/test/experimental/dataflow/TestUtil/NormalDataflowTest.qll b/python/ql/test/experimental/dataflow/TestUtil/NormalDataflowTest.qll index f526a1f43ae..a327886fedd 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/NormalDataflowTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/NormalDataflowTest.qll @@ -3,20 +3,20 @@ import experimental.dataflow.TestUtil.FlowTest import experimental.dataflow.testConfig private import semmle.python.dataflow.new.internal.PrintNode -class DataFlowTest extends FlowTest { - DataFlowTest() { this = "DataFlowTest" } +module DataFlowTest implements FlowTestSig { + string flowTag() { result = "flow" } - override string flowTag() { result = "flow" } - - override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { - exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) + predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + TestFlow::flow(source, sink) } } +import MakeFlowTest + query predicate missingAnnotationOnSink(Location location, string error, string element) { error = "ERROR, you should add `# $ MISSING: flow` annotation" and exists(DataFlow::Node sink | - any(TestConfiguration config).isSink(sink) and + TestConfig::isSink(sink) and // note: we only care about `SINK` and not `SINK_F`, so we have to reconstruct manually. exists(DataFlow::CallCfgNode call | call.getFunction().asCfgNode().(NameNode).getId() = "SINK" and @@ -24,8 +24,8 @@ query predicate missingAnnotationOnSink(Location location, string error, string ) and location = sink.getLocation() and element = prettyExpr(sink.asExpr()) and - not any(TestConfiguration config).hasFlow(_, sink) and - not exists(FalseNegativeExpectation missingResult | + not TestFlow::flowTo(sink) and + not exists(FalseNegativeTestExpectation missingResult | missingResult.getTag() = "flow" and missingResult.getLocation().getFile() = location.getFile() and missingResult.getLocation().getStartLine() = location.getStartLine() diff --git a/python/ql/test/experimental/dataflow/TestUtil/NormalTaintTrackingTest.qll b/python/ql/test/experimental/dataflow/TestUtil/NormalTaintTrackingTest.qll index 9619679da03..4a07dc4d2d6 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/NormalTaintTrackingTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/NormalTaintTrackingTest.qll @@ -3,16 +3,16 @@ import experimental.dataflow.TestUtil.FlowTest import experimental.dataflow.testTaintConfig private import semmle.python.dataflow.new.internal.PrintNode -class DataFlowTest extends FlowTest { - DataFlowTest() { this = "DataFlowTest" } +module DataFlowTest implements FlowTestSig { + string flowTag() { result = "flow" } - override string flowTag() { result = "flow" } - - override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { - exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) + predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + TestFlow::flow(source, sink) } } +import MakeFlowTest + query predicate missingAnnotationOnSink(Location location, string error, string element) { error = "ERROR, you should add `# $ MISSING: flow` annotation" and exists(DataFlow::Node sink | @@ -23,8 +23,8 @@ query predicate missingAnnotationOnSink(Location location, string error, string ) and location = sink.getLocation() and element = prettyExpr(sink.asExpr()) and - not any(TestConfiguration config).hasFlow(_, sink) and - not exists(FalseNegativeExpectation missingResult | + not TestFlow::flowTo(sink) and + not exists(FalseNegativeTestExpectation missingResult | missingResult.getTag() = "flow" and missingResult.getLocation().getFile() = location.getFile() and missingResult.getLocation().getStartLine() = location.getStartLine() diff --git a/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll b/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll index 003d02ba530..9b26d8c9175 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll @@ -4,11 +4,11 @@ private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPr private import semmle.python.ApiGraphs import TestUtilities.InlineExpectationsTest -class UnresolvedCallExpectations extends InlineExpectationsTest { - UnresolvedCallExpectations() { this = "UnresolvedCallExpectations" } - - override string getARelevantTag() { result = "unresolved_call" } +signature module UnresolvedCallExpectationsSig { + predicate unresolvedCall(CallNode call); +} +module DefaultUnresolvedCallExpectations implements UnresolvedCallExpectationsSig { predicate unresolvedCall(CallNode call) { not exists(DataFlowPrivate::DataFlowCall dfc | exists(dfc.getCallable()) and dfc.getNode() = call @@ -16,14 +16,22 @@ class UnresolvedCallExpectations extends InlineExpectationsTest { not DataFlowPrivate::resolveClassCall(call, _) and not call = API::builtin(_).getACall().asCfgNode() } - - override predicate hasActualResult(Location location, string element, string tag, string value) { - exists(location.getFile().getRelativePath()) and - exists(CallNode call | this.unresolvedCall(call) | - location = call.getLocation() and - tag = "unresolved_call" and - value = prettyExpr(call.getNode()) and - element = call.toString() - ) - } +} + +module MakeUnresolvedCallExpectations { + private module UnresolvedCallExpectations implements TestSig { + string getARelevantTag() { result = "unresolved_call" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(CallNode call | Impl::unresolvedCall(call) | + location = call.getLocation() and + tag = "unresolved_call" and + value = prettyExpr(call.getNode()) and + element = call.toString() + ) + } + } + + import MakeTest } diff --git a/python/ql/test/experimental/dataflow/basic/localFlowStepTest.expected b/python/ql/test/experimental/dataflow/basic/localFlowStepTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/experimental/dataflow/basic/localFlowStepTest.expected +++ b/python/ql/test/experimental/dataflow/basic/localFlowStepTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/experimental/dataflow/basic/maximalFlowTest.expected b/python/ql/test/experimental/dataflow/basic/maximalFlowTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/experimental/dataflow/basic/maximalFlowTest.expected +++ b/python/ql/test/experimental/dataflow/basic/maximalFlowTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/experimental/dataflow/coverage/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/coverage/NormalDataflowTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/experimental/dataflow/coverage/NormalDataflowTest.expected +++ b/python/ql/test/experimental/dataflow/coverage/NormalDataflowTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures diff --git a/python/ql/test/experimental/dataflow/exceptions/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/exceptions/NormalDataflowTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/experimental/dataflow/exceptions/NormalDataflowTest.expected +++ b/python/ql/test/experimental/dataflow/exceptions/NormalDataflowTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures diff --git a/python/ql/test/experimental/dataflow/fieldflow/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/fieldflow/NormalDataflowTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/experimental/dataflow/fieldflow/NormalDataflowTest.expected +++ b/python/ql/test/experimental/dataflow/fieldflow/NormalDataflowTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures diff --git a/python/ql/test/experimental/dataflow/fieldflow/UnresolvedCalls.expected b/python/ql/test/experimental/dataflow/fieldflow/UnresolvedCalls.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/experimental/dataflow/fieldflow/UnresolvedCalls.expected +++ b/python/ql/test/experimental/dataflow/fieldflow/UnresolvedCalls.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/experimental/dataflow/fieldflow/UnresolvedCalls.ql b/python/ql/test/experimental/dataflow/fieldflow/UnresolvedCalls.ql index af73ca552fc..3c7498bd651 100644 --- a/python/ql/test/experimental/dataflow/fieldflow/UnresolvedCalls.ql +++ b/python/ql/test/experimental/dataflow/fieldflow/UnresolvedCalls.ql @@ -2,11 +2,13 @@ import python import experimental.dataflow.TestUtil.UnresolvedCalls private import semmle.python.dataflow.new.DataFlow -class IgnoreDictMethod extends UnresolvedCallExpectations { - override predicate unresolvedCall(CallNode call) { - super.unresolvedCall(call) and +module IgnoreDictMethod implements UnresolvedCallExpectationsSig { + predicate unresolvedCall(CallNode call) { + DefaultUnresolvedCallExpectations::unresolvedCall(call) and not any(DataFlow::MethodCallNode methodCall | methodCall.getMethodName() in ["get", "setdefault"] ).asCfgNode() = call } } + +import MakeUnresolvedCallExpectations diff --git a/python/ql/test/experimental/dataflow/match/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/match/NormalDataflowTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/experimental/dataflow/match/NormalDataflowTest.expected +++ b/python/ql/test/experimental/dataflow/match/NormalDataflowTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures diff --git a/python/ql/test/experimental/dataflow/module-initialization/localFlow.expected b/python/ql/test/experimental/dataflow/module-initialization/localFlow.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/experimental/dataflow/module-initialization/localFlow.expected +++ b/python/ql/test/experimental/dataflow/module-initialization/localFlow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/experimental/dataflow/module-initialization/localFlow.ql b/python/ql/test/experimental/dataflow/module-initialization/localFlow.ql index 635902e7045..8ef3860955d 100644 --- a/python/ql/test/experimental/dataflow/module-initialization/localFlow.ql +++ b/python/ql/test/experimental/dataflow/module-initialization/localFlow.ql @@ -4,12 +4,10 @@ import experimental.dataflow.TestUtil.FlowTest private import semmle.python.dataflow.new.internal.PrintNode private import semmle.python.dataflow.new.internal.DataFlowPrivate as DP -class ImportTimeLocalFlowTest extends FlowTest { - ImportTimeLocalFlowTest() { this = "ImportTimeLocalFlowTest" } +module ImportTimeLocalFlowTest implements FlowTestSig { + string flowTag() { result = "importTimeFlow" } - override string flowTag() { result = "importTimeFlow" } - - override predicate relevantFlow(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + predicate relevantFlow(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { nodeFrom.getLocation().getFile().getBaseName() = "multiphase.py" and // results are displayed next to `nodeTo`, so we need a line to write on nodeTo.getLocation().getStartLine() > 0 and @@ -18,12 +16,10 @@ class ImportTimeLocalFlowTest extends FlowTest { } } -class RuntimeLocalFlowTest extends FlowTest { - RuntimeLocalFlowTest() { this = "RuntimeLocalFlowTest" } +module RuntimeLocalFlowTest implements FlowTestSig { + string flowTag() { result = "runtimeFlow" } - override string flowTag() { result = "runtimeFlow" } - - override predicate relevantFlow(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + predicate relevantFlow(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { nodeFrom.getLocation().getFile().getBaseName() = "multiphase.py" and // results are displayed next to `nodeTo`, so we need a line to write on nodeTo.getLocation().getStartLine() > 0 and @@ -34,3 +30,5 @@ class RuntimeLocalFlowTest extends FlowTest { DP::runtimeJumpStep(nodeFrom, nodeTo) } } + +import MakeFlowTest2 diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.ql b/python/ql/test/experimental/dataflow/regression/dataflow.ql index c95b2f2111f..39763fa4814 100644 --- a/python/ql/test/experimental/dataflow/regression/dataflow.ql +++ b/python/ql/test/experimental/dataflow/regression/dataflow.ql @@ -9,5 +9,5 @@ import python import experimental.dataflow.testConfig from DataFlow::Node source, DataFlow::Node sink -where exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) +where TestFlow::flow(source, sink) select source, sink diff --git a/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected b/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected +++ b/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures diff --git a/python/ql/test/experimental/dataflow/summaries/summaries.ql b/python/ql/test/experimental/dataflow/summaries/summaries.ql index f2c0a522279..d3c0206d41f 100644 --- a/python/ql/test/experimental/dataflow/summaries/summaries.ql +++ b/python/ql/test/experimental/dataflow/summaries/summaries.ql @@ -4,7 +4,7 @@ import python import semmle.python.dataflow.new.FlowSummary -import DataFlow::PathGraph +import TestFlow::PathGraph import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.internal.FlowSummaryImpl import semmle.python.ApiGraphs @@ -16,6 +16,6 @@ query predicate invalidSpecComponent(SummarizedCallable sc, string s, string c) Private::External::invalidSpecComponent(s, c) } -from DataFlow::PathNode source, DataFlow::PathNode sink, TestConfiguration conf -where conf.hasFlowPath(source, sink) +from TestFlow::PathNode source, TestFlow::PathNode sink +where TestFlow::flowPath(source, sink) select sink, source, sink, "$@", source, source.toString() diff --git a/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/InlineTaintTest.expected b/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/InlineTaintTest.expected +++ b/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/InlineTaintTest.ql b/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/InlineTaintTest.ql index 048d530dd41..46263250a9b 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/InlineTaintTest.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/InlineTaintTest.ql @@ -1,6 +1,12 @@ import experimental.meta.InlineTaintTest import semmle.python.dataflow.new.BarrierGuards -class CustomSanitizerOverrides extends TestTaintTrackingConfiguration { - override predicate isSanitizer(DataFlow::Node node) { node instanceof StringConstCompareBarrier } +module CustomSanitizerOverridesConfig implements DataFlow::ConfigSig { + predicate isSource = TestTaintTrackingConfig::isSource/1; + + predicate isSink = TestTaintTrackingConfig::isSink/1; + + predicate isBarrier(DataFlow::Node node) { node instanceof StringConstCompareBarrier } } + +import MakeInlineTaintTest diff --git a/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/InlineTaintTest.expected b/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/InlineTaintTest.expected index fdad063534b..6e4a1c072bc 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/InlineTaintTest.expected +++ b/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/InlineTaintTest.expected @@ -1,25 +1,26 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures isSanitizer -| TestTaintTrackingConfiguration | test.py:21:39:21:39 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test.py:34:39:34:39 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test.py:52:28:52:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test.py:66:10:66:29 | ControlFlowNode for emulated_escaping() | -| TestTaintTrackingConfiguration | test_logical.py:33:28:33:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:40:28:40:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:48:28:48:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:53:28:53:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:92:28:92:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:103:28:103:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:111:28:111:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:130:28:130:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:137:28:137:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:148:28:148:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:151:28:151:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:158:28:158:28 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:167:24:167:24 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:176:24:176:24 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:185:24:185:24 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_logical.py:193:24:193:24 | ControlFlowNode for s | -| TestTaintTrackingConfiguration | test_reference.py:31:28:31:28 | ControlFlowNode for s | +| test.py:21:39:21:39 | ControlFlowNode for s | +| test.py:34:39:34:39 | ControlFlowNode for s | +| test.py:52:28:52:28 | ControlFlowNode for s | +| test.py:66:10:66:29 | ControlFlowNode for emulated_escaping() | +| test_logical.py:33:28:33:28 | ControlFlowNode for s | +| test_logical.py:40:28:40:28 | ControlFlowNode for s | +| test_logical.py:48:28:48:28 | ControlFlowNode for s | +| test_logical.py:53:28:53:28 | ControlFlowNode for s | +| test_logical.py:92:28:92:28 | ControlFlowNode for s | +| test_logical.py:103:28:103:28 | ControlFlowNode for s | +| test_logical.py:111:28:111:28 | ControlFlowNode for s | +| test_logical.py:130:28:130:28 | ControlFlowNode for s | +| test_logical.py:137:28:137:28 | ControlFlowNode for s | +| test_logical.py:148:28:148:28 | ControlFlowNode for s | +| test_logical.py:151:28:151:28 | ControlFlowNode for s | +| test_logical.py:158:28:158:28 | ControlFlowNode for s | +| test_logical.py:167:24:167:24 | ControlFlowNode for s | +| test_logical.py:176:24:176:24 | ControlFlowNode for s | +| test_logical.py:185:24:185:24 | ControlFlowNode for s | +| test_logical.py:193:24:193:24 | ControlFlowNode for s | +| test_reference.py:31:28:31:28 | ControlFlowNode for s | diff --git a/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/InlineTaintTest.ql b/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/InlineTaintTest.ql index 984cf74d036..597f368b02f 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/InlineTaintTest.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/InlineTaintTest.ql @@ -12,8 +12,12 @@ predicate isUnsafeCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean bra branch = false } -class CustomSanitizerOverrides extends TestTaintTrackingConfiguration { - override predicate isSanitizer(DataFlow::Node node) { +module CustomSanitizerOverridesConfig implements DataFlow::ConfigSig { + predicate isSource = TestTaintTrackingConfig::isSource/1; + + predicate isSink = TestTaintTrackingConfig::isSink/1; + + predicate isBarrier(DataFlow::Node node) { exists(Call call | call.getFunc().(Name).getId() = "emulated_authentication_check" and call.getArg(0) = node.asExpr() @@ -27,7 +31,9 @@ class CustomSanitizerOverrides extends TestTaintTrackingConfiguration { } } -query predicate isSanitizer(TestTaintTrackingConfiguration conf, DataFlow::Node node) { +import MakeInlineTaintTest + +query predicate isSanitizer(DataFlow::Node node) { exists(node.getLocation().getFile().getRelativePath()) and - conf.isSanitizer(node) + CustomSanitizerOverridesConfig::isBarrier(node) } diff --git a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/InlineTaintTest.expected b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/InlineTaintTest.expected +++ b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/InlineTaintTest.ql b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/InlineTaintTest.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/InlineTaintTest.expected b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/InlineTaintTest.expected +++ b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/InlineTaintTest.ql b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/InlineTaintTest.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.expected b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.expected +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.ql b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.expected +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures diff --git a/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/InlineTaintTest.expected b/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/InlineTaintTest.expected +++ b/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/InlineTaintTest.ql b/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/InlineTaintTest.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/experimental/dataflow/testConfig.qll b/python/ql/test/experimental/dataflow/testConfig.qll index ab5f125d898..887f9e48e8e 100644 --- a/python/ql/test/experimental/dataflow/testConfig.qll +++ b/python/ql/test/experimental/dataflow/testConfig.qll @@ -23,10 +23,8 @@ private import python import semmle.python.dataflow.new.DataFlow -class TestConfiguration extends DataFlow::Configuration { - TestConfiguration() { this = "TestConfiguration" } - - override predicate isSource(DataFlow::Node node) { +module TestConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "SOURCE" or node.(DataFlow::CfgNode).getNode().getNode().(StrConst).getS() = "source" @@ -37,7 +35,7 @@ class TestConfiguration extends DataFlow::Configuration { // No support for complex numbers } - override predicate isSink(DataFlow::Node node) { + predicate isSink(DataFlow::Node node) { exists(DataFlow::CallCfgNode call | call.getFunction().asCfgNode().(NameNode).getId() in ["SINK", "SINK_F"] and (node = call.getArg(_) or node = call.getArgByName(_)) and @@ -45,5 +43,7 @@ class TestConfiguration extends DataFlow::Configuration { ) } - override predicate isBarrierIn(DataFlow::Node node) { this.isSource(node) } + predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } + +module TestFlow = DataFlow::Global; diff --git a/python/ql/test/experimental/dataflow/testTaintConfig.qll b/python/ql/test/experimental/dataflow/testTaintConfig.qll index 09496895c9a..89e9593c89f 100644 --- a/python/ql/test/experimental/dataflow/testTaintConfig.qll +++ b/python/ql/test/experimental/dataflow/testTaintConfig.qll @@ -24,10 +24,8 @@ private import python import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking -class TestConfiguration extends TaintTracking::Configuration { - TestConfiguration() { this = "TestConfiguration" } - - override predicate isSource(DataFlow::Node node) { +module TestConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "SOURCE" or node.(DataFlow::CfgNode).getNode().getNode().(StrConst).getS() = "source" @@ -38,12 +36,14 @@ class TestConfiguration extends TaintTracking::Configuration { // No support for complex numbers } - override predicate isSink(DataFlow::Node node) { + predicate isSink(DataFlow::Node node) { exists(CallNode call | call.getFunction().(NameNode).getId() in ["SINK", "SINK_F"] and node.(DataFlow::CfgNode).getNode() = call.getAnArg() ) } - override predicate isSanitizerIn(DataFlow::Node node) { this.isSource(node) } + predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } + +module TestFlow = TaintTracking::Global; diff --git a/python/ql/test/experimental/dataflow/typetracking/tracked.expected b/python/ql/test/experimental/dataflow/typetracking/tracked.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/experimental/dataflow/typetracking/tracked.expected +++ b/python/ql/test/experimental/dataflow/typetracking/tracked.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/experimental/dataflow/typetracking/tracked.ql b/python/ql/test/experimental/dataflow/typetracking/tracked.ql index c0ed62e258f..b6aa9d268d0 100644 --- a/python/ql/test/experimental/dataflow/typetracking/tracked.ql +++ b/python/ql/test/experimental/dataflow/typetracking/tracked.ql @@ -14,12 +14,10 @@ private DataFlow::TypeTrackingNode tracked(TypeTracker t) { exists(TypeTracker t2 | result = tracked(t2).track(t2, t)) } -class TrackedTest extends InlineExpectationsTest { - TrackedTest() { this = "TrackedTest" } +module TrackedTest implements TestSig { + string getARelevantTag() { result = "tracked" } - override string getARelevantTag() { result = "tracked" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node e, TypeTracker t | tracked(t).flowsTo(e) and // Module variables have no sensible location, and hence can't be annotated. @@ -54,12 +52,10 @@ private DataFlow::TypeTrackingNode string_type(TypeTracker t) { exists(TypeTracker t2 | result = string_type(t2).track(t2, t)) } -class TrackedIntTest extends InlineExpectationsTest { - TrackedIntTest() { this = "TrackedIntTest" } +module TrackedIntTest implements TestSig { + string getARelevantTag() { result = "int" } - override string getARelevantTag() { result = "int" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node e, TypeTracker t | int_type(t).flowsTo(e) and tag = "int" and @@ -70,12 +66,10 @@ class TrackedIntTest extends InlineExpectationsTest { } } -class TrackedStringTest extends InlineExpectationsTest { - TrackedStringTest() { this = "TrackedStringTest" } +module TrackedStringTest implements TestSig { + string getARelevantTag() { result = "str" } - override string getARelevantTag() { result = "str" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node e, TypeTracker t | string_type(t).flowsTo(e) and tag = "str" and @@ -100,12 +94,10 @@ private DataFlow::TypeTrackingNode tracked_self(TypeTracker t) { exists(TypeTracker t2 | result = tracked_self(t2).track(t2, t)) } -class TrackedSelfTest extends InlineExpectationsTest { - TrackedSelfTest() { this = "TrackedSelfTest" } +module TrackedSelfTest implements TestSig { + string getARelevantTag() { result = "tracked_self" } - override string getARelevantTag() { result = "tracked_self" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node e, TypeTracker t | tracked_self(t).flowsTo(e) and // Module variables have no sensible location, and hence can't be annotated. @@ -161,12 +153,10 @@ private DataFlow::TypeTrackingNode foo_bar_baz(DataFlow::TypeTracker t) { /** Gets a reference to `foo.bar.baz` (fictive attribute on `foo.bar` module). */ DataFlow::Node foo_bar_baz() { foo_bar_baz(DataFlow::TypeTracker::end()).flowsTo(result) } -class TrackedFooBarBaz extends InlineExpectationsTest { - TrackedFooBarBaz() { this = "TrackedFooBarBaz" } +module TrackedFooBarBaz implements TestSig { + string getARelevantTag() { result = "tracked_foo_bar_baz" } - override string getARelevantTag() { result = "tracked_foo_bar_baz" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node e | e = foo_bar_baz() and // Module variables have no sensible location, and hence can't be annotated. @@ -178,3 +168,5 @@ class TrackedFooBarBaz extends InlineExpectationsTest { ) } } + +import MakeTest> diff --git a/python/ql/test/experimental/dataflow/typetracking_imports/tracked.expected b/python/ql/test/experimental/dataflow/typetracking_imports/tracked.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/experimental/dataflow/typetracking_imports/tracked.expected +++ b/python/ql/test/experimental/dataflow/typetracking_imports/tracked.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/experimental/dataflow/variable-capture/CaptureTest.ql b/python/ql/test/experimental/dataflow/variable-capture/CaptureTest.ql index 68d15822cf6..a1c754e8ee5 100644 --- a/python/ql/test/experimental/dataflow/variable-capture/CaptureTest.ql +++ b/python/ql/test/experimental/dataflow/variable-capture/CaptureTest.ql @@ -7,7 +7,7 @@ module CaptureTest implements TestSig { string getARelevantTag() { result = "captured" } predicate hasActualResult(Location location, string element, string tag, string value) { - exists(DataFlow::Node sink | exists(TestConfiguration cfg | cfg.hasFlowTo(sink)) | + exists(DataFlow::Node sink | TestFlow::flowTo(sink) | location = sink.getLocation() and tag = "captured" and value = "" and diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 27c8cb99ab4..48803e11fb4 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -4,12 +4,10 @@ import semmle.python.Concepts import TestUtilities.InlineExpectationsTest private import semmle.python.dataflow.new.internal.PrintNode -class SystemCommandExecutionTest extends InlineExpectationsTest { - SystemCommandExecutionTest() { this = "SystemCommandExecutionTest" } +module SystemCommandExecutionTest implements TestSig { + string getARelevantTag() { result = "getCommand" } - override string getARelevantTag() { result = "getCommand" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(SystemCommandExecution sce, DataFlow::Node command | command = sce.getCommand() and @@ -21,14 +19,12 @@ class SystemCommandExecutionTest extends InlineExpectationsTest { } } -class DecodingTest extends InlineExpectationsTest { - DecodingTest() { this = "DecodingTest" } - - override string getARelevantTag() { +module DecodingTest implements TestSig { + string getARelevantTag() { result in ["decodeInput", "decodeOutput", "decodeFormat", "decodeMayExecuteInput"] } - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Decoding d | exists(DataFlow::Node data | @@ -61,12 +57,10 @@ class DecodingTest extends InlineExpectationsTest { } } -class EncodingTest extends InlineExpectationsTest { - EncodingTest() { this = "EncodingTest" } +module EncodingTest implements TestSig { + string getARelevantTag() { result in ["encodeInput", "encodeOutput", "encodeFormat"] } - override string getARelevantTag() { result in ["encodeInput", "encodeOutput", "encodeFormat"] } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Encoding e | exists(DataFlow::Node data | @@ -93,12 +87,10 @@ class EncodingTest extends InlineExpectationsTest { } } -class LoggingTest extends InlineExpectationsTest { - LoggingTest() { this = "LoggingTest" } +module LoggingTest implements TestSig { + string getARelevantTag() { result = "loggingInput" } - override string getARelevantTag() { result = "loggingInput" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Logging logging, DataFlow::Node data | location = data.getLocation() and @@ -110,12 +102,10 @@ class LoggingTest extends InlineExpectationsTest { } } -class CodeExecutionTest extends InlineExpectationsTest { - CodeExecutionTest() { this = "CodeExecutionTest" } +module CodeExecutionTest implements TestSig { + string getARelevantTag() { result = "getCode" } - override string getARelevantTag() { result = "getCode" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(CodeExecution ce, DataFlow::Node code | exists(location.getFile().getRelativePath()) and @@ -128,12 +118,10 @@ class CodeExecutionTest extends InlineExpectationsTest { } } -class SqlConstructionTest extends InlineExpectationsTest { - SqlConstructionTest() { this = "SqlConstructionTest" } +module SqlConstructionTest implements TestSig { + string getARelevantTag() { result = "constructedSql" } - override string getARelevantTag() { result = "constructedSql" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(SqlConstruction e, DataFlow::Node sql | exists(location.getFile().getRelativePath()) and @@ -146,12 +134,10 @@ class SqlConstructionTest extends InlineExpectationsTest { } } -class SqlExecutionTest extends InlineExpectationsTest { - SqlExecutionTest() { this = "SqlExecutionTest" } +module SqlExecutionTest implements TestSig { + string getARelevantTag() { result = "getSql" } - override string getARelevantTag() { result = "getSql" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(SqlExecution e, DataFlow::Node sql | exists(location.getFile().getRelativePath()) and @@ -164,12 +150,10 @@ class SqlExecutionTest extends InlineExpectationsTest { } } -class XPathConstructionTest extends InlineExpectationsTest { - XPathConstructionTest() { this = "XPathConstructionTest" } +module XPathConstructionTest implements TestSig { + string getARelevantTag() { result = "constructedXPath" } - override string getARelevantTag() { result = "constructedXPath" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(XML::XPathConstruction e, DataFlow::Node xpath | exists(location.getFile().getRelativePath()) and @@ -182,12 +166,10 @@ class XPathConstructionTest extends InlineExpectationsTest { } } -class XPathExecutionTest extends InlineExpectationsTest { - XPathExecutionTest() { this = "XPathExecutionTest" } +module XPathExecutionTest implements TestSig { + string getARelevantTag() { result = "getXPath" } - override string getARelevantTag() { result = "getXPath" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(XML::XPathExecution e, DataFlow::Node xpath | exists(location.getFile().getRelativePath()) and @@ -200,12 +182,10 @@ class XPathExecutionTest extends InlineExpectationsTest { } } -class EscapingTest extends InlineExpectationsTest { - EscapingTest() { this = "EscapingTest" } +module EscapingTest implements TestSig { + string getARelevantTag() { result in ["escapeInput", "escapeOutput", "escapeKind"] } - override string getARelevantTag() { result in ["escapeInput", "escapeOutput", "escapeKind"] } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Escaping esc | exists(DataFlow::Node data | @@ -232,12 +212,10 @@ class EscapingTest extends InlineExpectationsTest { } } -class HttpServerRouteSetupTest extends InlineExpectationsTest { - HttpServerRouteSetupTest() { this = "HttpServerRouteSetupTest" } +module HttpServerRouteSetupTest implements TestSig { + string getARelevantTag() { result = "routeSetup" } - override string getARelevantTag() { result = "routeSetup" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Http::Server::RouteSetup setup | location = setup.getLocation() and @@ -253,12 +231,10 @@ class HttpServerRouteSetupTest extends InlineExpectationsTest { } } -class HttpServerRequestHandlerTest extends InlineExpectationsTest { - HttpServerRequestHandlerTest() { this = "HttpServerRequestHandlerTest" } +module HttpServerRequestHandlerTest implements TestSig { + string getARelevantTag() { result in ["requestHandler", "routedParameter"] } - override string getARelevantTag() { result in ["requestHandler", "routedParameter"] } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and ( exists(Http::Server::RequestHandler handler | @@ -330,12 +306,10 @@ class HttpServerHttpResponseTest extends InlineExpectationsTest { } } -class HttpServerHttpRedirectResponseTest extends InlineExpectationsTest { - HttpServerHttpRedirectResponseTest() { this = "HttpServerHttpRedirectResponseTest" } +module HttpServerHttpRedirectResponseTest implements TestSig { + string getARelevantTag() { result in ["HttpRedirectResponse", "redirectLocation"] } - override string getARelevantTag() { result in ["HttpRedirectResponse", "redirectLocation"] } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and ( exists(Http::Server::HttpRedirectResponse redirect | @@ -355,14 +329,12 @@ class HttpServerHttpRedirectResponseTest extends InlineExpectationsTest { } } -class HttpServerCookieWriteTest extends InlineExpectationsTest { - HttpServerCookieWriteTest() { this = "HttpServerCookieWriteTest" } - - override string getARelevantTag() { +module HttpServerCookieWriteTest implements TestSig { + string getARelevantTag() { result in ["CookieWrite", "CookieRawHeader", "CookieName", "CookieValue"] } - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Http::Server::CookieWrite cookieWrite | location = cookieWrite.getLocation() and @@ -387,12 +359,10 @@ class HttpServerCookieWriteTest extends InlineExpectationsTest { } } -class FileSystemAccessTest extends InlineExpectationsTest { - FileSystemAccessTest() { this = "FileSystemAccessTest" } +module FileSystemAccessTest implements TestSig { + string getARelevantTag() { result = "getAPathArgument" } - override string getARelevantTag() { result = "getAPathArgument" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(FileSystemAccess a, DataFlow::Node path | path = a.getAPathArgument() and @@ -404,12 +374,10 @@ class FileSystemAccessTest extends InlineExpectationsTest { } } -class FileSystemWriteAccessTest extends InlineExpectationsTest { - FileSystemWriteAccessTest() { this = "FileSystemWriteAccessTest" } +module FileSystemWriteAccessTest implements TestSig { + string getARelevantTag() { result = "fileWriteData" } - override string getARelevantTag() { result = "fileWriteData" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(FileSystemWriteAccess write, DataFlow::Node data | data = write.getADataNode() and @@ -421,12 +389,10 @@ class FileSystemWriteAccessTest extends InlineExpectationsTest { } } -class PathNormalizationTest extends InlineExpectationsTest { - PathNormalizationTest() { this = "PathNormalizationTest" } +module PathNormalizationTest implements TestSig { + string getARelevantTag() { result = "pathNormalization" } - override string getARelevantTag() { result = "pathNormalization" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Path::PathNormalization n | location = n.getLocation() and @@ -437,12 +403,10 @@ class PathNormalizationTest extends InlineExpectationsTest { } } -class SafeAccessCheckTest extends InlineExpectationsTest { - SafeAccessCheckTest() { this = "SafeAccessCheckTest" } +module SafeAccessCheckTest implements TestSig { + string getARelevantTag() { result = "SafeAccessCheck" } - override string getARelevantTag() { result = "SafeAccessCheck" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Path::SafeAccessCheck c | location = c.getLocation() and @@ -453,12 +417,10 @@ class SafeAccessCheckTest extends InlineExpectationsTest { } } -class PublicKeyGenerationTest extends InlineExpectationsTest { - PublicKeyGenerationTest() { this = "PublicKeyGenerationTest" } +module PublicKeyGenerationTest implements TestSig { + string getARelevantTag() { result in ["PublicKeyGeneration", "keySize"] } - override string getARelevantTag() { result in ["PublicKeyGeneration", "keySize"] } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Cryptography::PublicKey::KeyGeneration keyGen | location = keyGen.getLocation() and @@ -475,17 +437,15 @@ class PublicKeyGenerationTest extends InlineExpectationsTest { } } -class CryptographicOperationTest extends InlineExpectationsTest { - CryptographicOperationTest() { this = "CryptographicOperationTest" } - - override string getARelevantTag() { +module CryptographicOperationTest implements TestSig { + string getARelevantTag() { result in [ "CryptographicOperation", "CryptographicOperationInput", "CryptographicOperationAlgorithm", "CryptographicOperationBlockMode" ] } - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Cryptography::CryptographicOperation cryptoOperation | location = cryptoOperation.getLocation() and @@ -510,14 +470,12 @@ class CryptographicOperationTest extends InlineExpectationsTest { } } -class HttpClientRequestTest extends InlineExpectationsTest { - HttpClientRequestTest() { this = "HttpClientRequestTest" } - - override string getARelevantTag() { +module HttpClientRequestTest implements TestSig { + string getARelevantTag() { result in ["clientRequestUrlPart", "clientRequestCertValidationDisabled"] } - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Http::Client::Request req, DataFlow::Node url | url = req.getAUrlPart() and @@ -538,12 +496,10 @@ class HttpClientRequestTest extends InlineExpectationsTest { } } -class CsrfProtectionSettingTest extends InlineExpectationsTest { - CsrfProtectionSettingTest() { this = "CsrfProtectionSettingTest" } +module CsrfProtectionSettingTest implements TestSig { + string getARelevantTag() { result = "CsrfProtectionSetting" } - override string getARelevantTag() { result = "CsrfProtectionSetting" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Http::Server::CsrfProtectionSetting setting | location = setting.getLocation() and @@ -554,12 +510,10 @@ class CsrfProtectionSettingTest extends InlineExpectationsTest { } } -class CsrfLocalProtectionSettingTest extends InlineExpectationsTest { - CsrfLocalProtectionSettingTest() { this = "CsrfLocalProtectionSettingTest" } +module CsrfLocalProtectionSettingTest implements TestSig { + string getARelevantTag() { result = "CsrfLocalProtection" + ["Enabled", "Disabled"] } - override string getARelevantTag() { result = "CsrfLocalProtection" + ["Enabled", "Disabled"] } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(Http::Server::CsrfLocalProtectionSetting p | location = p.getLocation() and @@ -572,12 +526,10 @@ class CsrfLocalProtectionSettingTest extends InlineExpectationsTest { } } -class XmlParsingTest extends InlineExpectationsTest { - XmlParsingTest() { this = "XmlParsingTest" } +module XmlParsingTest implements TestSig { + string getARelevantTag() { result = "xmlVuln" } - override string getARelevantTag() { result = "xmlVuln" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(XML::XmlParsing parsing, XML::XmlParsingVulnerabilityKind kind | parsing.vulnerableTo(kind) and @@ -588,3 +540,14 @@ class XmlParsingTest extends InlineExpectationsTest { ) } } + +import MakeTest, + MergeTests5, + MergeTests4, + MergeTests5, + MergeTests5>> diff --git a/python/ql/test/experimental/meta/InlineTaintTest.qll b/python/ql/test/experimental/meta/InlineTaintTest.qll index 9982ec961d4..24f67bcf2a4 100644 --- a/python/ql/test/experimental/meta/InlineTaintTest.qll +++ b/python/ql/test/experimental/meta/InlineTaintTest.qll @@ -33,10 +33,8 @@ DataFlow::Node shouldNotBeTainted() { // this module allows the configuration to be imported in other `.ql` files without the // top level query predicates of this file coming into scope. module Conf { - class TestTaintTrackingConfiguration extends TaintTracking::Configuration { - TestTaintTrackingConfiguration() { this = "TestTaintTrackingConfiguration" } - - override predicate isSource(DataFlow::Node source) { + module TestTaintTrackingConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asCfgNode().(NameNode).getId() in [ "TAINTED_STRING", "TAINTED_BYTES", "TAINTED_LIST", "TAINTED_DICT" ] @@ -50,7 +48,7 @@ module Conf { source instanceof RemoteFlowSource } - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { sink = shouldBeTainted() or sink = shouldNotBeTainted() @@ -60,49 +58,53 @@ module Conf { import Conf -class InlineTaintTest extends InlineExpectationsTest { - InlineTaintTest() { this = "InlineTaintTest" } +module MakeInlineTaintTest { + private module Flow = TaintTracking::Global; - override string getARelevantTag() { result = "tainted" } + private module InlineTaintTest implements TestSig { + string getARelevantTag() { result = "tainted" } - override predicate hasActualResult(Location location, string element, string tag, string value) { - exists(location.getFile().getRelativePath()) and + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(DataFlow::Node sink | + Flow::flowTo(sink) and + location = sink.getLocation() and + element = prettyExpr(sink.asExpr()) and + value = "" and + tag = "tainted" + ) + } + } + + import MakeTest + + query predicate argumentToEnsureNotTaintedNotMarkedAsSpurious( + Location location, string error, string element + ) { + error = "ERROR, you should add `SPURIOUS:` to this annotation" and + location = shouldNotBeTainted().getLocation() and + InlineTaintTest::hasActualResult(location, element, "tainted", _) and + exists(GoodTestExpectation good, ActualTestResult actualResult | + good.matchesActualResult(actualResult) and + actualResult.getLocation() = location and + actualResult.toString() = element + ) + } + + query predicate untaintedArgumentToEnsureTaintedNotMarkedAsMissing( + Location location, string error, string element + ) { + error = "ERROR, you should add `# $ MISSING: tainted` annotation" and exists(DataFlow::Node sink | - any(TestTaintTrackingConfiguration config).hasFlow(_, sink) and - location = sink.getLocation() and + sink = shouldBeTainted() and element = prettyExpr(sink.asExpr()) and - value = "" and - tag = "tainted" + not Flow::flowTo(sink) and + location = sink.getLocation() and + not exists(FalseNegativeTestExpectation missingResult | + missingResult.getTag() = "tainted" and + missingResult.getLocation().getFile() = location.getFile() and + missingResult.getLocation().getStartLine() = location.getStartLine() + ) ) } } - -query predicate argumentToEnsureNotTaintedNotMarkedAsSpurious( - Location location, string error, string element -) { - error = "ERROR, you should add `SPURIOUS:` to this annotation" and - location = shouldNotBeTainted().getLocation() and - any(InlineTaintTest test).hasActualResult(location, element, "tainted", _) and - exists(GoodExpectation good, ActualResult actualResult | - good.matchesActualResult(actualResult) and - actualResult.getLocation() = location and - actualResult.toString() = element - ) -} - -query predicate untaintedArgumentToEnsureTaintedNotMarkedAsMissing( - Location location, string error, string element -) { - error = "ERROR, you should add `# $ MISSING: tainted` annotation" and - exists(DataFlow::Node sink | - sink = shouldBeTainted() and - element = prettyExpr(sink.asExpr()) and - not any(TestTaintTrackingConfiguration config).hasFlow(_, sink) and - location = sink.getLocation() and - not exists(FalseNegativeExpectation missingResult | - missingResult.getTag() = "tainted" and - missingResult.getLocation().getFile() = location.getFile() and - missingResult.getLocation().getStartLine() = location.getStartLine() - ) - ) -} diff --git a/python/ql/test/experimental/meta/MaDTest.qll b/python/ql/test/experimental/meta/MaDTest.qll index a4b5877f5ea..9b6bd59287a 100644 --- a/python/ql/test/experimental/meta/MaDTest.qll +++ b/python/ql/test/experimental/meta/MaDTest.qll @@ -7,16 +7,14 @@ private import semmle.python.Frameworks // this import needs to be public to get the query predicates propagated to the actual test files import TestUtilities.InlineExpectationsTest -class MadSinkTest extends InlineExpectationsTest { - MadSinkTest() { this = "MadSinkTest" } - - override string getARelevantTag() { +module MadSinkTest implements TestSig { + string getARelevantTag() { exists(string kind | exists(ModelOutput::getASinkNode(kind)) | result = "mad-sink[" + kind + "]" ) } - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(DataFlow::Node sink, string kind | sink = ModelOutput::getASinkNode(kind).asSink() and @@ -28,14 +26,12 @@ class MadSinkTest extends InlineExpectationsTest { } } -class MadSourceTest extends InlineExpectationsTest { - MadSourceTest() { this = "MadSourceTest" } - - override string getARelevantTag() { +module MadSourceTest implements TestSig { + string getARelevantTag() { exists(string kind | exists(ModelOutput::getASourceNode(kind)) | result = "mad-source__" + kind) } - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(DataFlow::Node source, string kind | source = ModelOutput::getASourceNode(kind).asSource() and @@ -46,3 +42,5 @@ class MadSourceTest extends InlineExpectationsTest { ) } } + +import MakeTest> diff --git a/python/ql/test/experimental/meta/debug/InlineTaintTestPaths.ql b/python/ql/test/experimental/meta/debug/InlineTaintTestPaths.ql index 98ad634484e..3f082f21fa4 100644 --- a/python/ql/test/experimental/meta/debug/InlineTaintTestPaths.ql +++ b/python/ql/test/experimental/meta/debug/InlineTaintTestPaths.ql @@ -13,11 +13,9 @@ import semmle.python.dataflow.new.TaintTracking import experimental.meta.InlineTaintTest::Conf module Config implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { - any(TestTaintTrackingConfiguration c).isSource(source) - } + predicate isSource(DataFlow::Node source) { TestTaintTrackingConfig::isSource(source) } - predicate isSink(DataFlow::Node source) { any(TestTaintTrackingConfiguration c).isSink(source) } + predicate isSink(DataFlow::Node source) { TestTaintTrackingConfig::isSink(source) } } module Flows = TaintTracking::Global; diff --git a/python/ql/test/experimental/meta/debug/dataflowTestPaths.ql b/python/ql/test/experimental/meta/debug/dataflowTestPaths.ql index 087787f4fc1..3e2d625de77 100644 --- a/python/ql/test/experimental/meta/debug/dataflowTestPaths.ql +++ b/python/ql/test/experimental/meta/debug/dataflowTestPaths.ql @@ -12,9 +12,9 @@ import semmle.python.dataflow.new.DataFlow import experimental.dataflow.testConfig module Config implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { any(TestConfiguration c).isSource(source) } + predicate isSource(DataFlow::Node source) { TestConfig::isSource(source) } - predicate isSink(DataFlow::Node source) { any(TestConfiguration c).isSink(source) } + predicate isSink(DataFlow::Node source) { TestConfig::isSink(source) } } module Flows = DataFlow::Global; diff --git a/python/ql/test/experimental/meta/inline-taint-test-demo/InlineTaintTest.expected b/python/ql/test/experimental/meta/inline-taint-test-demo/InlineTaintTest.expected index 745561a5e65..511dc50d5ca 100644 --- a/python/ql/test/experimental/meta/inline-taint-test-demo/InlineTaintTest.expected +++ b/python/ql/test/experimental/meta/inline-taint-test-demo/InlineTaintTest.expected @@ -1,7 +1,8 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious | taint_test.py:48:9:48:29 | taint_test.py:48 | ERROR, you should add `SPURIOUS:` to this annotation | should_not_be_tainted | untaintedArgumentToEnsureTaintedNotMarkedAsMissing | taint_test.py:32:9:32:25 | taint_test.py:32 | ERROR, you should add `# $ MISSING: tainted` annotation | should_be_tainted | | taint_test.py:37:24:37:40 | taint_test.py:37 | ERROR, you should add `# $ MISSING: tainted` annotation | should_be_tainted | -failures +testFailures | taint_test.py:41:20:41:21 | ts | Fixed missing result:tainted= | diff --git a/python/ql/test/experimental/meta/inline-taint-test-demo/InlineTaintTest.ql b/python/ql/test/experimental/meta/inline-taint-test-demo/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/experimental/meta/inline-taint-test-demo/InlineTaintTest.ql +++ b/python/ql/test/experimental/meta/inline-taint-test-demo/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/aioch/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/aioch/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/aioch/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/aioch/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/aiohttp/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/aiohttp/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/aiohttp/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/aiohttp/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/aiomysql/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/aiomysql/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/aiomysql/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/aiomysql/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/aiopg/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/aiopg/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/aiopg/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/aiopg/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/aiosqlite/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/aiosqlite/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/aiosqlite/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/aiosqlite/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/asyncpg/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/asyncpg/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/asyncpg/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/asyncpg/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/asyncpg/MaDTest.expected b/python/ql/test/library-tests/frameworks/asyncpg/MaDTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/asyncpg/MaDTest.expected +++ b/python/ql/test/library-tests/frameworks/asyncpg/MaDTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/cassandra-driver/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/cassandra-driver/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/cassandra-driver/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/cassandra-driver/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/clickhouse_driver/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/clickhouse_driver/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/clickhouse_driver/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/clickhouse_driver/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/crypto/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/crypto/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/crypto/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/crypto/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/cryptodome/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/cryptodome/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/cryptodome/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/cryptodome/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/cryptography/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/cryptography/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/cryptography/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/cryptography/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/cx_Oracle/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/cx_Oracle/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/cx_Oracle/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/cx_Oracle/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/dill/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/dill/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/dill/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/dill/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/django-orm/NormalDataflowTest.expected b/python/ql/test/library-tests/frameworks/django-orm/NormalDataflowTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/library-tests/frameworks/django-orm/NormalDataflowTest.expected +++ b/python/ql/test/library-tests/frameworks/django-orm/NormalDataflowTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/django-v1/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/django-v1/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/django-v1/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/django-v1/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/django-v2-v3/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/django-v2-v3/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/django-v2-v3/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/django/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/django/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/django/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/django/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/fabric/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/fabric/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/fabric/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/fabric/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/fabric/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/fabric/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/fabric/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/fabric/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/fabric/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/fabric/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/fabric/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/fabric/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/fastapi/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/fastapi/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/fastapi/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/fastapi/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/flask/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/flask/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/flask/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/flask/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/flask/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/flask/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/flask/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/flask/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/flask/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/flask/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/flask/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/flask/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/flask_admin/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/flask_admin/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/flask_admin/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/flask_admin/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/flask_admin/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/flask_admin/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/flask_admin/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/flask_admin/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/flask_admin/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/flask_admin/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/flask_admin/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/flask_admin/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/flask_sqlalchemy/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/flask_sqlalchemy/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/flask_sqlalchemy/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/flask_sqlalchemy/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/flask_sqlalchemy/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/flask_sqlalchemy/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/flask_sqlalchemy/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/flask_sqlalchemy/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/flask_sqlalchemy/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/flask_sqlalchemy/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/flask_sqlalchemy/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/flask_sqlalchemy/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/httpx/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/httpx/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/httpx/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/httpx/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/idna/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/idna/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/idna/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/idna/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/idna/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/idna/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/idna/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/idna/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/idna/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/idna/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/idna/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/idna/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/invoke/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/invoke/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/invoke/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/invoke/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/jmespath/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/jmespath/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/jmespath/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/jmespath/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/jmespath/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/jmespath/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/jmespath/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/jmespath/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/jmespath/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/jmespath/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/jmespath/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/jmespath/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/libtaxii/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/libtaxii/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/libtaxii/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/libtaxii/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/lxml/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/lxml/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/lxml/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/lxml/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/markupsafe/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/markupsafe/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/markupsafe/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/markupsafe/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/markupsafe/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/markupsafe/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/markupsafe/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/markupsafe/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/markupsafe/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/markupsafe/InlineTaintTest.ql index 993da68784e..8fd0d08c56a 100644 --- a/python/ql/test/library-tests/frameworks/markupsafe/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/markupsafe/InlineTaintTest.ql @@ -1,7 +1,11 @@ import experimental.meta.InlineTaintTest import semmle.python.Concepts -class HtmlSpecialization extends TestTaintTrackingConfiguration { +module HtmlSpecializationConfig implements DataFlow::ConfigSig { + predicate isSource = TestTaintTrackingConfig::isSource/1; + + predicate isSink = TestTaintTrackingConfig::isSink/1; + // TODO: For now, since there is not an `isSanitizingStep` member-predicate part of a // `TaintTracking::Configuration`, we use treat the output is a taint-sanitizer. This // is slightly imprecise, which you can see in the `m_unsafe + SAFE` test-case in @@ -9,5 +13,7 @@ class HtmlSpecialization extends TestTaintTrackingConfiguration { // // However, it is better than `getAnInput()`. Due to use-use flow, that would remove // the taint-flow to `SINK()` in `some_escape(tainted); SINK(tainted)`. - override predicate isSanitizer(DataFlow::Node node) { node = any(HtmlEscaping esc).getOutput() } + predicate isBarrier(DataFlow::Node node) { node = any(HtmlEscaping esc).getOutput() } } + +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/multidict/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/multidict/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/multidict/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/multidict/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/multidict/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/multidict/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/multidict/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/multidict/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/multidict/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/multidict/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/multidict/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/multidict/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/mysql-connector-python/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/mysql-connector-python/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/mysql-connector-python/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/mysql-connector-python/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/mysqldb/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/mysqldb/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/mysqldb/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/mysqldb/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/oracledb/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/oracledb/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/oracledb/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/oracledb/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/peewee/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/peewee/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/peewee/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/peewee/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/phoenixdb/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/phoenixdb/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/phoenixdb/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/phoenixdb/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/pycurl/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/pycurl/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/pycurl/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/pycurl/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/pymssql/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/pymssql/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/pymssql/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/pymssql/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/pymysql/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/pymysql/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/pymysql/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/pymysql/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/pyodbc/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/pyodbc/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/pyodbc/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/pyodbc/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/requests/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/requests/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/requests/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/requests/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/requests/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/requests/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/requests/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/requests/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/requests/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/requests/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/requests/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/requests/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/rest_framework/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/rest_framework/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/rest_framework/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/rest_framework/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/rest_framework/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/rest_framework/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/rest_framework/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/rest_framework/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/rest_framework/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/rest_framework/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/rest_framework/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/rest_framework/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/rsa/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/rsa/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/rsa/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/rsa/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/rsa/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/rsa/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/rsa/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/rsa/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/rsa/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/rsa/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/rsa/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/rsa/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/ruamel.yaml/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/ruamel.yaml/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/ruamel.yaml/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/ruamel.yaml/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/simplejson/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/simplejson/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/simplejson/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/simplejson/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/simplejson/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/simplejson/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/simplejson/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/simplejson/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/simplejson/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/simplejson/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/simplejson/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/simplejson/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/stdlib-py3/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/stdlib-py3/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/stdlib-py3/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/stdlib-py3/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/stdlib/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/stdlib/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/stdlib/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/toml/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/toml/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/toml/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/toml/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/tornado/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/tornado/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/tornado/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/tornado/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/tornado/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/tornado/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/tornado/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/tornado/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/tornado/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/tornado/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/tornado/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/tornado/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/twisted/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/twisted/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/twisted/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/twisted/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/twisted/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/twisted/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/twisted/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/twisted/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/twisted/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/twisted/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/twisted/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/twisted/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/ujson/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/ujson/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/ujson/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/ujson/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/ujson/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/ujson/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/ujson/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/ujson/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/ujson/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/ujson/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/ujson/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/ujson/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/frameworks/urllib3/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/urllib3/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/urllib3/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/urllib3/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/xmltodict/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/yaml/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/yaml/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/yaml/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/yaml/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/yarl/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/yarl/ConceptsTest.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/frameworks/yarl/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/yarl/ConceptsTest.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/yarl/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/yarl/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/library-tests/frameworks/yarl/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/yarl/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/library-tests/frameworks/yarl/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/yarl/InlineTaintTest.ql index 027ad8667be..8524da5fe7d 100644 --- a/python/ql/test/library-tests/frameworks/yarl/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/yarl/InlineTaintTest.ql @@ -1 +1,2 @@ import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/library-tests/regex/SubstructureTests.expected b/python/ql/test/library-tests/regex/SubstructureTests.expected index e69de29bb2d..48de9172b36 100644 --- a/python/ql/test/library-tests/regex/SubstructureTests.expected +++ b/python/ql/test/library-tests/regex/SubstructureTests.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/python/ql/test/library-tests/regex/SubstructureTests.ql b/python/ql/test/library-tests/regex/SubstructureTests.ql index e189c13b15e..f575670e16a 100644 --- a/python/ql/test/library-tests/regex/SubstructureTests.ql +++ b/python/ql/test/library-tests/regex/SubstructureTests.ql @@ -2,12 +2,10 @@ import python import TestUtilities.InlineExpectationsTest private import semmle.python.regex -class CharacterSetTest extends InlineExpectationsTest { - CharacterSetTest() { this = "CharacterSetTest" } +module CharacterSetTest implements TestSig { + string getARelevantTag() { result = "charSet" } - override string getARelevantTag() { result = "charSet" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and location.getFile().getBaseName() = "charSetTest.py" and exists(RegExp re, int start, int end | @@ -20,12 +18,10 @@ class CharacterSetTest extends InlineExpectationsTest { } } -class CharacterRangeTest extends InlineExpectationsTest { - CharacterRangeTest() { this = "CharacterRangeTest" } +module CharacterRangeTest implements TestSig { + string getARelevantTag() { result = "charRange" } - override string getARelevantTag() { result = "charRange" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and location.getFile().getBaseName() = "charRangeTest.py" and exists(RegExp re, int start, int lower_end, int upper_start, int end | @@ -38,12 +34,10 @@ class CharacterRangeTest extends InlineExpectationsTest { } } -class EscapeTest extends InlineExpectationsTest { - EscapeTest() { this = "EscapeTest" } +module EscapeTest implements TestSig { + string getARelevantTag() { result = "escapedCharacter" } - override string getARelevantTag() { result = "escapedCharacter" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and location.getFile().getBaseName() = "escapedCharacterTest.py" and exists(RegExp re, int start, int end | @@ -56,12 +50,10 @@ class EscapeTest extends InlineExpectationsTest { } } -class GroupTest extends InlineExpectationsTest { - GroupTest() { this = "GroupTest" } +module GroupTest implements TestSig { + string getARelevantTag() { result = "group" } - override string getARelevantTag() { result = "group" } - - override predicate hasActualResult(Location location, string element, string tag, string value) { + predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and location.getFile().getBaseName() = "groupTest.py" and exists(RegExp re, int start, int end | @@ -73,3 +65,5 @@ class GroupTest extends InlineExpectationsTest { ) } } + +import MakeTest> diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.expected b/python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.expected +++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.expected b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.expected +++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures diff --git a/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/DataflowQueryTest.expected b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/DataflowQueryTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/DataflowQueryTest.expected +++ b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/DataflowQueryTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures From e111a19524421bb97a1b2342e6714d4c34cec0de Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 19 Jun 2023 11:41:41 +0200 Subject: [PATCH 206/364] python: split tests into taint and value and add summaries --- .../model-summaries/TestSummaries.qll | 8 --- .../NormalDataflowTest.expected} | 0 .../dataflow/NormalDataflowTest.ql | 3 + .../dataflow/TestSummaries.qll | 20 ++++++ .../dataflow/model_summaries.py | 69 +++++++++++++++++++ .../taint/NormalTaintTrackingTest.expected | 2 + .../{ => taint}/NormalTaintTrackingTest.ql | 0 .../model-summaries/taint/TestSummaries.qll | 19 +++++ .../model_summaries_taint.py} | 20 +++--- 9 files changed, 123 insertions(+), 18 deletions(-) delete mode 100644 python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll rename python/ql/test/experimental/dataflow/model-summaries/{NormalTaintTrackingTest.expected => dataflow/NormalDataflowTest.expected} (100%) create mode 100644 python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.ql create mode 100644 python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll create mode 100644 python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py create mode 100644 python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected rename python/ql/test/experimental/dataflow/model-summaries/{ => taint}/NormalTaintTrackingTest.ql (100%) create mode 100644 python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll rename python/ql/test/experimental/dataflow/model-summaries/{model_summaries.py => taint/model_summaries_taint.py} (62%) diff --git a/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll b/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll deleted file mode 100644 index 5069c406a60..00000000000 --- a/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll +++ /dev/null @@ -1,8 +0,0 @@ -private import python -private import semmle.python.dataflow.new.FlowSummary -private import semmle.python.frameworks.data.ModelsAsData -private import semmle.python.ApiGraphs - -private class StepsFromModel extends ModelInput::SummaryModelCsv { - override predicate row(string row) { none() } -} diff --git a/python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.expected b/python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.expected similarity index 100% rename from python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.expected rename to python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.expected diff --git a/python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.ql b/python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.ql new file mode 100644 index 00000000000..3e311335e14 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.ql @@ -0,0 +1,3 @@ +import python +private import TestSummaries +import experimental.dataflow.TestUtil.NormalDataflowTest diff --git a/python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll b/python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll new file mode 100644 index 00000000000..d97702eec41 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll @@ -0,0 +1,20 @@ +private import python +private import semmle.python.dataflow.new.FlowSummary +private import semmle.python.frameworks.data.ModelsAsData +private import semmle.python.ApiGraphs + +private class StepsFromModel extends ModelInput::SummaryModelCsv { + override predicate row(string row) { + row = + [ + "Foo;Member[MS_identity];Argument[0];ReturnValue;value", + "Foo;Member[MS_apply_lambda];Argument[1];Argument[0].Parameter[0];value", + "Foo;Member[MS_apply_lambda];Argument[0].ReturnValue;ReturnValue;value", + "Foo;Member[MS_reversed];Argument[0].ListElement;ReturnValue.ListElement;value", + "Foo;Member[MS_list_map];Argument[1].ListElement;Argument[0].Parameter[0];value", + "Foo;Member[MS_list_map];Argument[0].ReturnValue;ReturnValue.ListElement;value", + "Foo;Member[MS_append_to_list];Argument[0].ListElement;ReturnValue.ListElement;value", + "Foo;Member[MS_append_to_list];Argument[1];ReturnValue.ListElement;value" + ] + } +} diff --git a/python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py new file mode 100644 index 00000000000..c81fddf44ec --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py @@ -0,0 +1,69 @@ + +import sys +import os + +sys.path.append(os.path.dirname(os.path.dirname((__file__)))) +from testlib import expects + +# These are defined so that we can evaluate the test code. +NONSOURCE = "not a source" +SOURCE = "source" + + +def is_source(x): + return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j + + +def SINK(x): + if is_source(x): + print("OK") + else: + print("Unexpected flow", x) + + +def SINK_F(x): + if is_source(x): + print("Unexpected flow", x) + else: + print("OK") + + +from Foo import MS_identity, MS_apply_lambda, MS_reversed, MS_list_map, MS_append_to_list + +# Simple summary +tainted = MS_identity(SOURCE) +SINK(tainted) # $ flow="SOURCE, l:-1 -> tainted" + +# Lambda summary +tainted_lambda = MS_apply_lambda(lambda x: [x], SOURCE) +SINK(tainted_lambda[0]) # $ flow="SOURCE, l:-1 -> tainted_lambda[0]" + +# A lambda that breaks the flow +untainted_lambda = MS_apply_lambda(lambda x: 1, SOURCE) +SINK_F(untainted_lambda) + +# Collection summaries +tainted_list = MS_reversed([SOURCE]) +SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" + +# Complex summaries +def box(x): + return [x] + +tainted_mapped = MS_list_map(box, [SOURCE]) +SINK(tainted_mapped[0][0]) # $ flow="SOURCE, l:-1 -> tainted_mapped[0][0]" + +def explicit_identity(x): + return x + +tainted_mapped_explicit = MS_list_map(explicit_identity, [SOURCE]) +SINK(tainted_mapped_explicit[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" + +tainted_mapped_summary = MS_list_map(MS_identity, [SOURCE]) +SINK(tainted_mapped_summary[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" + +tainted_list = MS_append_to_list([], SOURCE) +SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" + +tainted_list = MS_append_to_list([SOURCE], NONSOURCE) +SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" diff --git a/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected b/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected new file mode 100644 index 00000000000..3875da4e143 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected @@ -0,0 +1,2 @@ +missingAnnotationOnSink +failures diff --git a/python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.ql b/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.ql similarity index 100% rename from python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.ql rename to python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.ql diff --git a/python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll b/python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll new file mode 100644 index 00000000000..57861d3c022 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll @@ -0,0 +1,19 @@ +private import python +private import semmle.python.dataflow.new.FlowSummary +private import semmle.python.frameworks.data.ModelsAsData +private import semmle.python.ApiGraphs + +private class StepsFromModel extends ModelInput::SummaryModelCsv { + override predicate row(string row) { + row = + [ + "Foo;Member[MS_identity];Argument[0];ReturnValue;value", + "Foo;Member[MS_apply_lambda];Argument[1];Argument[0].Parameter[0];value", + "Foo;Member[MS_apply_lambda];Argument[0].ReturnValue;ReturnValue;value", + "Foo;Member[MS_reversed];Argument[0];ReturnValue;taint", + "Foo;Member[MS_list_map];Argument[1];ReturnValue;taint", + "Foo;Member[MS_append_to_list];Argument[0];ReturnValue;taint", + "json;Member[MS_loads];Argument[0];ReturnValue;taint" + ] + } +} diff --git a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/taint/model_summaries_taint.py similarity index 62% rename from python/ql/test/experimental/dataflow/model-summaries/model_summaries.py rename to python/ql/test/experimental/dataflow/model-summaries/taint/model_summaries_taint.py index 23cc4990aba..44ca79c116e 100644 --- a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py +++ b/python/ql/test/experimental/dataflow/model-summaries/taint/model_summaries_taint.py @@ -28,15 +28,15 @@ def SINK_F(x): print("OK") -from Foo import MS_identity +from Foo import MS_identity, MS_apply_lambda, MS_reversed, MS_list_map, MS_append_to_list # Simple summary tainted = MS_identity(SOURCE) -SINK(tainted) # $ MISSING: flow="SOURCE, l:-1 -> tainted" +SINK(tainted) # $ flow="SOURCE, l:-1 -> tainted" # Lambda summary tainted_lambda = MS_apply_lambda(lambda x: x + 1, SOURCE) -SINK(tainted_lambda) # $ MISSING: flow="SOURCE, l:-1 -> tainted_lambda" +SINK(tainted_lambda) # $ flow="SOURCE, l:-1 -> tainted_lambda" # A lambda that breaks the flow untainted_lambda = MS_apply_lambda(lambda x: 1, SOURCE) @@ -44,27 +44,27 @@ SINK_F(untainted_lambda) # Collection summaries tainted_list = MS_reversed([SOURCE]) -SINK(tainted_list[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_list[0]" +SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" # Complex summaries def add_colon(x): return x + ":" tainted_mapped = MS_list_map(add_colon, [SOURCE]) -SINK(tainted_mapped[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped[0]" +SINK(tainted_mapped[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped[0]" def explicit_identity(x): return x tainted_mapped_explicit = MS_list_map(explicit_identity, [SOURCE]) -SINK(tainted_mapped_explicit[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" +SINK(tainted_mapped_explicit[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" tainted_mapped_summary = MS_list_map(MS_identity, [SOURCE]) -SINK(tainted_mapped_summary[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" +SINK(tainted_mapped_summary[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" -tainted_list = MS_append_to_list([], SOURCE) -SINK(tainted_list[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_list[0]" +tainted_list = MS_append_to_list([SOURCE], NONSOURCE) +SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" from json import MS_loads as json_loads tainted_resultlist = json_loads(SOURCE) -SINK(tainted_resultlist[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_resultlist[0]" +SINK(tainted_resultlist[0]) # $ flow="SOURCE, l:-1 -> tainted_resultlist[0]" From a01169eec2a29e1e8f74844c54232f2c48f1be19 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Jun 2023 14:22:39 +0100 Subject: [PATCH 207/364] add "Dereference" content for PointerContent --- go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 2 ++ .../semmle/go/dataflow/ExternalFlow/completetest.ext.yml | 4 ++-- .../library-tests/semmle/go/dataflow/ExternalFlow/test.go | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 0c6ee1c3134..f04ce005794 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -342,6 +342,8 @@ predicate parseContent(string component, DataFlow::Content content) { component = "MapKey" and content instanceof DataFlow::MapKeyContent or component = "MapValue" and content instanceof DataFlow::MapValueContent + or + component = "Dereference" and content instanceof DataFlow::PointerContent } cached diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml index 4ec8602daaf..47e51e573f0 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml @@ -22,9 +22,9 @@ extensions: - ["github.com/nonexistent/test", "", False, "GetMapKey", "", "", "Argument[0].MapKey", "ReturnValue", "value", "manual"] - ["github.com/nonexistent/test", "", False, "SetElement", "", "", "Argument[0]", "ReturnValue.Element", "value", "manual"] - ["github.com/nonexistent/test", "C", False, "Get", "", "", "Argument[-1].Field[github.com/nonexistent/test.C.F]", "ReturnValue", "value", "manual"] - - ["github.com/nonexistent/test", "C", False, "GetThroughPointer", "", "", "Argument[-1].Field[github.com/nonexistent/test.C.F]", "ReturnValue", "value", "manual"] + - ["github.com/nonexistent/test", "C", False, "GetThroughPointer", "", "", "Argument[-1].Dereference.Field[github.com/nonexistent/test.C.F]", "ReturnValue", "value", "manual"] - ["github.com/nonexistent/test", "C", False, "Set", "", "", "Argument[0]", "Argument[-1].Field[github.com/nonexistent/test.C.F]", "value", "manual"] - - ["github.com/nonexistent/test", "C", False, "SetThroughPointer", "", "", "Argument[0]", "Argument[-1].Field[github.com/nonexistent/test.C.F]", "value", "manual"] + - ["github.com/nonexistent/test", "C", False, "SetThroughPointer", "", "", "Argument[0]", "Argument[-1].Dereference.Field[github.com/nonexistent/test.C.F]", "value", "manual"] - addsTo: pack: codeql/go-all diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/test.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/test.go index 0d92787b65c..35da086a888 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/test.go +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/test.go @@ -143,10 +143,10 @@ func simpleflow() { cp1 := &test.C{""} cp1.SetThroughPointer(a.Src1().(string)) - b.Sink1(cp1.F) // $ MISSING: hasTaintFlow="selection of F" + b.Sink1(cp1.F) // $ hasTaintFlow="selection of F" cp2 := &test.C{a.Src1().(string)} - b.Sink1(cp2.GetThroughPointer()) // $ MISSING: hasTaintFlow="call to GetThroughPointer" + b.Sink1(cp2.GetThroughPointer()) // $ hasTaintFlow="call to GetThroughPointer" cp3 := &test.C{""} cp3.SetThroughPointer(a.Src1().(string)) From 5ceac5a77110d7da6f44899ed059dfc6aa717de0 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 20 Jun 2023 11:53:31 +0200 Subject: [PATCH 208/364] python: add changenote --- .../ql/lib/change-notes/2023-06-20-summaries-from-models.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/lib/change-notes/2023-06-20-summaries-from-models.md diff --git a/python/ql/lib/change-notes/2023-06-20-summaries-from-models.md b/python/ql/lib/change-notes/2023-06-20-summaries-from-models.md new file mode 100644 index 00000000000..feded1bb6c5 --- /dev/null +++ b/python/ql/lib/change-notes/2023-06-20-summaries-from-models.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* It is now possible to specify flow summaries in the format "MyPkg;Member[list_map];Argument[1].ListElement;Argument[0].Parameter[0];value" From 81142f51fbede42d6ee5607b3546e3f0922c9d17 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Fri, 16 Jun 2023 13:33:41 +0100 Subject: [PATCH 209/364] Kotlin: Handle IrSyntheticBodyKind.ENUM_ENTRIES Generated by Kotlin 1.9 for some of our tests. --- .../src/main/kotlin/KotlinFileExtractor.kt | 11 ++++++----- .../utils/versions/v_1_4_32/SyntheticBodyKind.kt | 6 ++++++ .../utils/versions/v_1_8_0/SyntheticBodyKind.kt | 6 ++++++ java/ql/lib/config/semmlecode.dbscheme | 1 + 4 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/SyntheticBodyKind.kt create mode 100644 java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/SyntheticBodyKind.kt diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index a3bc20d9eda..8eece83083a 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -1701,12 +1701,13 @@ open class KotlinFileExtractor( private fun extractSyntheticBody(b: IrSyntheticBody, callable: Label) { with("synthetic body", b) { - when (b.kind) { - IrSyntheticBodyKind.ENUM_VALUES -> tw.writeKtSyntheticBody(callable, 1) - IrSyntheticBodyKind.ENUM_VALUEOF -> tw.writeKtSyntheticBody(callable, 2) + val kind = b.kind + when { + kind == IrSyntheticBodyKind.ENUM_VALUES -> tw.writeKtSyntheticBody(callable, 1) + kind == IrSyntheticBodyKind.ENUM_VALUEOF -> tw.writeKtSyntheticBody(callable, 2) + kind == kind_ENUM_ENTRIES -> tw.writeKtSyntheticBody(callable, 3) else -> { - // TODO: Support IrSyntheticBodyKind.ENUM_ENTRIES - logger.errorElement("Unhandled synthetic body kind " + b.kind.javaClass, b) + logger.errorElement("Unhandled synthetic body kind " + kind, b) } } } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/SyntheticBodyKind.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/SyntheticBodyKind.kt new file mode 100644 index 00000000000..fd3fc1f8e20 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/SyntheticBodyKind.kt @@ -0,0 +1,6 @@ +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind + +val kind_ENUM_ENTRIES: IrSyntheticBodyKind? = null + diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/SyntheticBodyKind.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/SyntheticBodyKind.kt new file mode 100644 index 00000000000..d0dbb5b1247 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/SyntheticBodyKind.kt @@ -0,0 +1,6 @@ +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind + +val kind_ENUM_ENTRIES: IrSyntheticBodyKind? = IrSyntheticBodyKind.ENUM_ENTRIES + diff --git a/java/ql/lib/config/semmlecode.dbscheme b/java/ql/lib/config/semmlecode.dbscheme index 7cbc85b1f3e..ecfcf050952 100644 --- a/java/ql/lib/config/semmlecode.dbscheme +++ b/java/ql/lib/config/semmlecode.dbscheme @@ -1219,6 +1219,7 @@ ktSyntheticBody( int kind: int ref // 1: ENUM_VALUES // 2: ENUM_VALUEOF + // 3: ENUM_ENTRIES ) ktLocalFunction( From 0076d8aac1161a8fc736ae158b67beae127bcda2 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Fri, 16 Jun 2023 13:36:31 +0100 Subject: [PATCH 210/364] Java: Add up/downgrade scripts --- .../old.dbscheme | 1256 +++++++++++++++++ .../semmlecode.dbscheme | 1255 ++++++++++++++++ .../upgrade.properties | 2 + .../old.dbscheme | 1255 ++++++++++++++++ .../semmlecode.dbscheme | 1256 +++++++++++++++++ .../upgrade.properties | 2 + 6 files changed, 5026 insertions(+) create mode 100644 java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/old.dbscheme create mode 100644 java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/semmlecode.dbscheme create mode 100644 java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/upgrade.properties create mode 100644 java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/old.dbscheme create mode 100644 java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/semmlecode.dbscheme create mode 100644 java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/upgrade.properties diff --git a/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/old.dbscheme b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/old.dbscheme new file mode 100644 index 00000000000..ecfcf050952 --- /dev/null +++ b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/old.dbscheme @@ -0,0 +1,1256 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @classorinterface ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @classorinterface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF + // 3: ENUM_ENTRIES +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/semmlecode.dbscheme b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/semmlecode.dbscheme new file mode 100644 index 00000000000..7cbc85b1f3e --- /dev/null +++ b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/semmlecode.dbscheme @@ -0,0 +1,1255 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @classorinterface ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @classorinterface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/upgrade.properties b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/upgrade.properties new file mode 100644 index 00000000000..5ba64f71d70 --- /dev/null +++ b/java/downgrades/ecfcf050952e54b1155fc89525db84af6ad34aaf/upgrade.properties @@ -0,0 +1,2 @@ +description: Remove ENUM_ENTRIES +compatibility: full diff --git a/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/old.dbscheme b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/old.dbscheme new file mode 100644 index 00000000000..7cbc85b1f3e --- /dev/null +++ b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/old.dbscheme @@ -0,0 +1,1255 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @classorinterface ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @classorinterface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/semmlecode.dbscheme b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/semmlecode.dbscheme new file mode 100644 index 00000000000..ecfcf050952 --- /dev/null +++ b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/semmlecode.dbscheme @@ -0,0 +1,1256 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @classorinterface ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @classorinterface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF + // 3: ENUM_ENTRIES +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/upgrade.properties b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/upgrade.properties new file mode 100644 index 00000000000..47074bcc8ab --- /dev/null +++ b/java/ql/lib/upgrades/7cbc85b1f3ecda39661ad4806dedbd0973d2c4c0/upgrade.properties @@ -0,0 +1,2 @@ +description: Add ENUM_ENTRIES +compatibility: full From 293f90333d1929bcb1317abf9323896c3bf1d473 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Fri, 16 Jun 2023 17:04:47 +0100 Subject: [PATCH 211/364] Kotlin: Avoid another cause of ConcurrentModificationException with 1.9 --- java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index 8eece83083a..39fd82a77ea 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -5317,7 +5317,10 @@ open class KotlinFileExtractor( private fun extractTypeAccessRecursive(t: IrType, location: Label, parent: Label, idx: Int, typeContext: TypeContext = TypeContext.OTHER): Label { val typeAccessId = extractTypeAccess(useType(t, typeContext), location, parent, idx) if (t is IrSimpleType) { - t.arguments.forEachIndexed { argIdx, arg -> + // From 1.9, the list might change when we call erase, + // so we make a copy that it is safe to iterate over. + val argumentsCopy = t.arguments.toList() + argumentsCopy.forEachIndexed { argIdx, arg -> extractWildcardTypeAccessRecursive(arg, location, typeAccessId, argIdx) } } From 732b14ee3800204db6c9820f33e2cf6a50c8bb95 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 20 Jun 2023 11:04:03 +0100 Subject: [PATCH 212/364] Update pretty printing predicates --- .../lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll index 41ae6b50ce3..609790659f8 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll @@ -106,6 +106,8 @@ private string getContentSpecific(Content c) { c instanceof MapKeyContent and result = "MapKey" or c instanceof MapValueContent and result = "MapValue" + or + c instanceof PointerContent and result = "Dereference" } /** Gets the textual representation of the content in the format used for flow summaries. */ From 04ff89e1feecc7b6240c5d9e6d580cc09ca50f03 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 20 Jun 2023 11:05:05 +0100 Subject: [PATCH 213/364] Update access path documentation --- .../lib/semmle/code/csharp/dataflow/ExternalFlow.qll | 4 ++-- go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index 46a19828a81..fbf5217a7f0 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -62,8 +62,8 @@ * in the given range. The range is inclusive at both ends. * - "ReturnValue": Selects the return value of a call to the selected element. * - * For summaries, `input` and `output` may be prefixed by one of the following, - * separated by the "of" keyword: + * For summaries, `input` and `output` may be suffixed by any number of the + * following, separated by ".": * - "Element": Selects an element in a collection. * - "Field[f]": Selects the contents of field `f`. * - "Property[p]": Selects the contents of property `p`. diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index f04ce005794..ab46c9206e8 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -54,6 +54,18 @@ * return value. The return values are zero-indexed * - "ReturnValue[n1..n2]": Similar to "ReturnValue[n]" but selects any * return value in the given range. The range is inclusive at both ends. + * + * For summaries, `input` and `output` may be suffixed by any number of the + * following, separated by ".": + * - "Field[pkg.className.fieldname]": Selects the contents of the field `f` + * which satisfies `f.hasQualifiedName(pkg, className, fieldname)`. + * - "SyntheticField[f]": Selects the contents of the synthetic field `f`. + * - "ArrayElement": Selects an element in an array or slice. + * - "Element": Selects an element in a collection. + * - "MapKey": Selects a key in a map. + * - "MapValue": Selects a value in a map. + * - "Dereference": Selects the value referenced by a pointer. + * * 8. The `kind` column is a tag that can be referenced from QL to determine to * which classes the interpreted elements should be added. For example, for * sources "remote" indicates a default remote flow source, and for summaries From 18b678e69e211d91a704c97567d7a12c9e5ef174 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 20 Jun 2023 10:20:05 +0000 Subject: [PATCH 214/364] Post-release preparation for codeql-cli-2.13.4 --- cpp/ql/lib/qlpack.yml | 2 +- cpp/ql/src/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +- csharp/ql/lib/qlpack.yml | 2 +- csharp/ql/src/qlpack.yml | 2 +- go/ql/lib/qlpack.yml | 2 +- go/ql/src/qlpack.yml | 2 +- java/ql/lib/qlpack.yml | 2 +- java/ql/src/qlpack.yml | 2 +- javascript/ql/lib/qlpack.yml | 2 +- javascript/ql/src/qlpack.yml | 2 +- misc/suite-helpers/qlpack.yml | 2 +- python/ql/lib/qlpack.yml | 2 +- python/ql/src/qlpack.yml | 2 +- ruby/ql/lib/qlpack.yml | 2 +- ruby/ql/src/qlpack.yml | 2 +- shared/regex/qlpack.yml | 2 +- shared/ssa/qlpack.yml | 2 +- shared/tutorial/qlpack.yml | 2 +- shared/typetracking/qlpack.yml | 2 +- shared/typos/qlpack.yml | 2 +- shared/util/qlpack.yml | 2 +- shared/yaml/qlpack.yml | 2 +- swift/ql/lib/qlpack.yml | 2 +- swift/ql/src/qlpack.yml | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 2d39cafe571..0065372f811 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 0.7.3 +version: 0.7.4-dev groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index 1aa38f466f6..077b34194fb 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 0.6.3 +version: 0.6.4-dev groups: - cpp - queries diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index d48f3cb1b0a..5f8c63b8ea3 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.5.3 +version: 1.5.4-dev groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index f63efb58811..65153d150f7 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.5.3 +version: 1.5.4-dev groups: - csharp - solorigate diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 833f7eae10b..9ead1290662 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 0.6.3 +version: 0.6.4-dev groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index 0ae9d1d6c03..91cba09b8ac 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 0.6.3 +version: 0.6.4-dev groups: - csharp - queries diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index ce44cff6d9e..0fe9af73882 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 0.5.3 +version: 0.5.4-dev groups: go dbscheme: go.dbscheme extractor: go diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 65c84860754..ad8b0d5db16 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 0.5.3 +version: 0.5.4-dev groups: - go - queries diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 8a18f2bdabb..81392376fd1 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 0.6.3 +version: 0.6.4-dev groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index b52ce1fd59c..b75aea1c0a0 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 0.6.3 +version: 0.6.4-dev groups: - java - queries diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index bda9945c1c3..021a8719e54 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 0.6.3 +version: 0.6.4-dev groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index 6df72dd450f..a1a1ed2b4f2 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 0.6.3 +version: 0.6.4-dev groups: - javascript - queries diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index 60af5875e10..f07f050124a 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,3 +1,3 @@ name: codeql/suite-helpers -version: 0.5.3 +version: 0.5.4-dev groups: shared diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index 101ed2a7232..ff2c246a618 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 0.9.3 +version: 0.9.4-dev groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index 3c274ee84a9..7dd13516d8b 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 0.7.3 +version: 0.7.4-dev groups: - python - queries diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index 2591c99f5cf..d7c154febf3 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 0.6.3 +version: 0.6.4-dev groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index f98583c5f80..6e1eb058cd4 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 0.6.3 +version: 0.6.4-dev groups: - ruby - queries diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml index 63d34ec6329..03c1586d407 100644 --- a/shared/regex/qlpack.yml +++ b/shared/regex/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/regex -version: 0.0.14 +version: 0.0.15-dev groups: shared library: true dependencies: diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index be427812ded..c3fdb224479 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ssa -version: 0.0.18 +version: 0.0.19-dev groups: shared library: true warnOnImplicitThis: true diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml index 9d655dcca3e..7dc19224a82 100644 --- a/shared/tutorial/qlpack.yml +++ b/shared/tutorial/qlpack.yml @@ -1,6 +1,6 @@ name: codeql/tutorial description: Library for the CodeQL detective tutorials, helping new users learn to write CodeQL queries. -version: 0.0.11 +version: 0.0.12-dev groups: shared library: true warnOnImplicitThis: true diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml index ca6b6a9c76e..09ae3c23605 100644 --- a/shared/typetracking/qlpack.yml +++ b/shared/typetracking/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typetracking -version: 0.0.11 +version: 0.0.12-dev groups: shared library: true dependencies: diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml index b3796de8fa1..65a104d1f01 100644 --- a/shared/typos/qlpack.yml +++ b/shared/typos/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typos -version: 0.0.18 +version: 0.0.19-dev groups: shared library: true warnOnImplicitThis: true diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index f48343df59f..5dce17506ce 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/util -version: 0.0.11 +version: 0.0.12-dev groups: shared library: true dependencies: diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml index e379f9bd9e1..ffbf802a8c4 100644 --- a/shared/yaml/qlpack.yml +++ b/shared/yaml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/yaml -version: 0.0.3 +version: 0.0.4-dev groups: shared library: true warnOnImplicitThis: true diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index 5993dfaefcf..ccce91fd9c1 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-all -version: 0.1.1 +version: 0.1.2-dev groups: swift extractor: swift dbscheme: swift.dbscheme diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml index 3393d61d8d6..9fac028053b 100644 --- a/swift/ql/src/qlpack.yml +++ b/swift/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-queries -version: 0.1.1 +version: 0.1.2-dev groups: - swift - queries From 7837959bdf10790606f5e90e63d8a11f913d1fa0 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 20 Jun 2023 11:58:32 +0200 Subject: [PATCH 215/364] QL: Add query to find Android queries with improper ids --- ql/ql/src/queries/style/AndroidIdPrefix.ql | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 ql/ql/src/queries/style/AndroidIdPrefix.ql diff --git a/ql/ql/src/queries/style/AndroidIdPrefix.ql b/ql/ql/src/queries/style/AndroidIdPrefix.ql new file mode 100644 index 00000000000..46071b08784 --- /dev/null +++ b/ql/ql/src/queries/style/AndroidIdPrefix.ql @@ -0,0 +1,32 @@ +/** + * @name Android query without android @id prefix + * @description Android queries should include the `android` prefix in their `@id`. + * @kind problem + * @problem.severity warning + * @id ql/android-id-prefix + * @precision high + */ + +import ql + +string getIdProperty(QLDoc doc) { + result = any(string id | id = doc.getContents().splitAt("@") and id.matches("id %")) +} + +predicate importsAndroidModule(TopLevel t) { + exists(Import i | t.getAnImport() = i | + i.getImportString().toLowerCase().matches("%android%") + or + exists(TopLevel t2 | + t2.getAModule() = i.getResolvedModule().asModule() and + importsAndroidModule(t2) + ) + ) +} + +from TopLevel t +where + t.getLocation().getFile().getRelativePath().matches("%src/Security/%.ql") and + not getIdProperty(t.getQLDoc()).matches("% java/android/%") and + importsAndroidModule(t) +select t, "This Android query is missing the `android` prefix in its `@id`." From 150854603b147f5e6eb70472ea851de25f09ce1e Mon Sep 17 00:00:00 2001 From: Tiago Pascoal Date: Tue, 20 Jun 2023 11:38:27 +0100 Subject: [PATCH 216/364] Single quote was preventing the shell from expanding the BODY variable While this prevents the attack highlighted in the query help it also prevents it from working. Double quotes will allow the expansion of the variable while still preventing the attack --- .../ql/src/Security/CWE-094/examples/comment_issue_good.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-094/examples/comment_issue_good.yml b/javascript/ql/src/Security/CWE-094/examples/comment_issue_good.yml index 22d6554076c..07254a8b204 100644 --- a/javascript/ql/src/Security/CWE-094/examples/comment_issue_good.yml +++ b/javascript/ql/src/Security/CWE-094/examples/comment_issue_good.yml @@ -7,4 +7,4 @@ jobs: - env: BODY: ${{ github.event.issue.body }} run: | - echo '$BODY' \ No newline at end of file + echo "$BODY" From e4e91c7ab08054af8014b4c421205e421cb49d70 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Tue, 20 Jun 2023 12:17:43 +0100 Subject: [PATCH 217/364] mention how instantiation-nested predicates are treated in stratification and evaluation --- docs/codeql/ql-language-reference/ql-language-specification.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst index 32244023c21..3cd76fc0512 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -2046,6 +2046,8 @@ A valid stratification must include each predicate and type in the QL program th A valid stratification must not include the same predicate in multiple layers. +Each non-abstract predicate has an associated body. For predicates inside *declared modules*, this is the predicate declaration. The body of an *instantiation-nested* predicate is the body of the *underlying nested* predicate where all references and calls have been substituted with the *instantiation-relative* entity or alias. + Formulas, variable declarations and expressions within a predicate body have a *negation polarity* that is positive, negative, or zero. Positive and negative are opposites of each other, while zero is the opposite of itself. The negation polarity of a formula or expression is then determined as follows: - The body of a predicate is positive. From 971456c725db04312abee65ee111c8e62eec5f8c Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 14 Jun 2023 13:18:29 -0400 Subject: [PATCH 218/364] C++: add a test for self-valued iterators --- .../dataflow/dataflow-tests/self-Iterator.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp new file mode 100644 index 00000000000..c02644d3f10 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp @@ -0,0 +1,21 @@ +#include "../../../include/iterator.h" +int source(); + +template +void sink(T); + +template<> struct std::iterator_traits +{ // get traits from integer type + typedef std::input_iterator_tag iterator_category; + typedef unsigned long value_type; + typedef unsigned long difference_type; + typedef unsigned long distance_type; + typedef unsigned long * pointer; + typedef unsigned long& reference; +}; + + +int test() { + unsigned long x = source(); + sink(x); // $ ast MISSING: ir +} \ No newline at end of file From 952dbd69e928b3204738a2a83f32b0517632ca90 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 20 Jun 2023 12:58:11 +0100 Subject: [PATCH 219/364] C++: Default to one indirection in the case of self iterators. --- .../cpp/ir/dataflow/internal/SsaInternalsCommon.qll | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll index d8571b8b74a..356a02e1cf9 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll @@ -117,6 +117,16 @@ private int countIndirections(Type t) { else ( result = any(Indirection ind | ind.getType() = t).getNumberOfIndirections() or + // If there is an indirection for the type, but we cannot count the number of indirections + // it means we couldn't reach a non-indirection type by stripping off indirections. This + // can occur if an iterator specifies itself as the value type. In this case we default to + // 1 indirection fore the type. + exists(Indirection ind | + ind.getType() = t and + not exists(ind.getNumberOfIndirections()) and + result = 1 + ) + or not exists(Indirection ind | ind.getType() = t) and result = 0 ) From 2b0282ca1255bcba465ce7769d9e52f4e960a00d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 20 Jun 2023 12:58:17 +0100 Subject: [PATCH 220/364] C++: Accept test changes. --- .../library-tests/dataflow/dataflow-tests/self-Iterator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp index c02644d3f10..cac7f222c30 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/self-Iterator.cpp @@ -17,5 +17,5 @@ template<> struct std::iterator_traits int test() { unsigned long x = source(); - sink(x); // $ ast MISSING: ir + sink(x); // $ ast ir } \ No newline at end of file From cc320c5e9cc217709bd10b5ac4b0cbe5d94de56d Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Jun 2023 15:44:47 +0100 Subject: [PATCH 221/364] Never skip functionmodel inputs and outputs in path summaries --- go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll index 277c92703e7..99d22d5c4e8 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll @@ -232,7 +232,11 @@ class CastNode extends ExprNode { * Holds if `n` should never be skipped over in the `PathGraph` and in path * explanations. */ -predicate neverSkipInPathGraph(Node n) { none() } +predicate neverSkipInPathGraph(Node n) { + exists(DataFlow::FunctionModel fm | fm.getAnInputNode(_) = n or fm.getAnOutputNode(_) = n) + or + exists(TaintTracking::FunctionModel fm | fm.getAnInputNode(_) = n or fm.getAnOutputNode(_) = n) +} class DataFlowExpr = Expr; From c0fea8538033820f6bfff97fb86c2fde13fa2ea2 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 16 Jun 2023 16:13:11 +0100 Subject: [PATCH 222/364] Accept test changes --- .../CWE-134/DsnInjection.expected | 6 +- .../CWE-134/DsnInjectionLocal.expected | 19 ++++-- go/ql/test/experimental/CWE-918/SSRF.expected | 24 +++++-- .../go/frameworks/Beego/ReflectedXss.expected | 4 +- .../Security/CWE-022/TaintedPath.expected | 4 +- .../Security/CWE-022/ZipSlip.expected | 4 +- .../CWE-078/CommandInjection.expected | 62 ++++++++++++++++--- .../Security/CWE-078/StoredCommand.expected | 7 ++- .../Security/CWE-079/ReflectedXss.expected | 24 +++++-- .../Security/CWE-079/StoredXss.expected | 7 ++- .../Security/CWE-089/SqlInjection.expected | 44 ++++++++++--- .../Security/CWE-327/UnsafeTLS.expected | 22 ++++++- .../InsecureRandomness.expected | 8 ++- .../CWE-352/ConstantOauth2State.expected | 4 +- 14 files changed, 194 insertions(+), 45 deletions(-) diff --git a/go/ql/test/experimental/CWE-134/DsnInjection.expected b/go/ql/test/experimental/CWE-134/DsnInjection.expected index de054067a01..531bdb0ead2 100644 --- a/go/ql/test/experimental/CWE-134/DsnInjection.expected +++ b/go/ql/test/experimental/CWE-134/DsnInjection.expected @@ -1,7 +1,11 @@ edges -| Dsn.go:47:10:47:30 | call to FormValue | Dsn.go:50:29:50:33 | dbDSN | +| Dsn.go:47:10:47:30 | call to FormValue | Dsn.go:49:102:49:105 | name | +| Dsn.go:49:11:49:106 | call to Sprintf | Dsn.go:50:29:50:33 | dbDSN | +| Dsn.go:49:102:49:105 | name | Dsn.go:49:11:49:106 | call to Sprintf | nodes | Dsn.go:47:10:47:30 | call to FormValue | semmle.label | call to FormValue | +| Dsn.go:49:11:49:106 | call to Sprintf | semmle.label | call to Sprintf | +| Dsn.go:49:102:49:105 | name | semmle.label | name | | Dsn.go:50:29:50:33 | dbDSN | semmle.label | dbDSN | subpaths #select diff --git a/go/ql/test/experimental/CWE-134/DsnInjectionLocal.expected b/go/ql/test/experimental/CWE-134/DsnInjectionLocal.expected index de5e959d43f..762c5bf3e04 100644 --- a/go/ql/test/experimental/CWE-134/DsnInjectionLocal.expected +++ b/go/ql/test/experimental/CWE-134/DsnInjectionLocal.expected @@ -1,25 +1,34 @@ edges -| Dsn.go:26:11:26:17 | selection of Args | Dsn.go:29:29:29:33 | dbDSN | +| Dsn.go:26:11:26:17 | selection of Args | Dsn.go:28:102:28:109 | index expression | +| Dsn.go:28:11:28:110 | call to Sprintf | Dsn.go:29:29:29:33 | dbDSN | +| Dsn.go:28:102:28:109 | index expression | Dsn.go:28:11:28:110 | call to Sprintf | | Dsn.go:62:2:62:4 | definition of cfg [pointer] | Dsn.go:63:9:63:11 | cfg [pointer] | | Dsn.go:62:2:62:4 | definition of cfg [pointer] | Dsn.go:67:102:67:104 | cfg [pointer] | | Dsn.go:63:9:63:11 | cfg [pointer] | Dsn.go:63:9:63:11 | implicit dereference | | Dsn.go:63:9:63:11 | implicit dereference | Dsn.go:62:2:62:4 | definition of cfg [pointer] | | Dsn.go:63:9:63:11 | implicit dereference | Dsn.go:63:9:63:11 | implicit dereference | -| Dsn.go:63:9:63:11 | implicit dereference | Dsn.go:68:29:68:33 | dbDSN | -| Dsn.go:63:19:63:25 | selection of Args | Dsn.go:63:9:63:11 | implicit dereference | -| Dsn.go:63:19:63:25 | selection of Args | Dsn.go:68:29:68:33 | dbDSN | +| Dsn.go:63:9:63:11 | implicit dereference | Dsn.go:67:102:67:108 | selection of dsn | +| Dsn.go:63:19:63:25 | selection of Args | Dsn.go:63:19:63:29 | slice expression | +| Dsn.go:63:19:63:29 | slice expression | Dsn.go:63:9:63:11 | implicit dereference | +| Dsn.go:67:11:67:109 | call to Sprintf | Dsn.go:68:29:68:33 | dbDSN | | Dsn.go:67:102:67:104 | cfg [pointer] | Dsn.go:67:102:67:104 | implicit dereference | | Dsn.go:67:102:67:104 | implicit dereference | Dsn.go:63:9:63:11 | implicit dereference | -| Dsn.go:67:102:67:104 | implicit dereference | Dsn.go:68:29:68:33 | dbDSN | +| Dsn.go:67:102:67:104 | implicit dereference | Dsn.go:67:102:67:108 | selection of dsn | +| Dsn.go:67:102:67:108 | selection of dsn | Dsn.go:67:11:67:109 | call to Sprintf | nodes | Dsn.go:26:11:26:17 | selection of Args | semmle.label | selection of Args | +| Dsn.go:28:11:28:110 | call to Sprintf | semmle.label | call to Sprintf | +| Dsn.go:28:102:28:109 | index expression | semmle.label | index expression | | Dsn.go:29:29:29:33 | dbDSN | semmle.label | dbDSN | | Dsn.go:62:2:62:4 | definition of cfg [pointer] | semmle.label | definition of cfg [pointer] | | Dsn.go:63:9:63:11 | cfg [pointer] | semmle.label | cfg [pointer] | | Dsn.go:63:9:63:11 | implicit dereference | semmle.label | implicit dereference | | Dsn.go:63:19:63:25 | selection of Args | semmle.label | selection of Args | +| Dsn.go:63:19:63:29 | slice expression | semmle.label | slice expression | +| Dsn.go:67:11:67:109 | call to Sprintf | semmle.label | call to Sprintf | | Dsn.go:67:102:67:104 | cfg [pointer] | semmle.label | cfg [pointer] | | Dsn.go:67:102:67:104 | implicit dereference | semmle.label | implicit dereference | +| Dsn.go:67:102:67:108 | selection of dsn | semmle.label | selection of dsn | | Dsn.go:68:29:68:33 | dbDSN | semmle.label | dbDSN | subpaths #select diff --git a/go/ql/test/experimental/CWE-918/SSRF.expected b/go/ql/test/experimental/CWE-918/SSRF.expected index 5ba4e98208e..d5a4910ad0d 100644 --- a/go/ql/test/experimental/CWE-918/SSRF.expected +++ b/go/ql/test/experimental/CWE-918/SSRF.expected @@ -4,17 +4,23 @@ edges | builtin.go:97:21:97:31 | call to Referer | builtin.go:101:36:101:49 | untrustedInput | | builtin.go:111:21:111:31 | call to Referer | builtin.go:114:15:114:28 | untrustedInput | | builtin.go:129:21:129:31 | call to Referer | builtin.go:132:38:132:51 | untrustedInput | -| new-tests.go:26:26:26:30 | &... | new-tests.go:31:11:31:57 | call to Sprintf | -| new-tests.go:26:26:26:30 | &... | new-tests.go:32:11:32:57 | call to Sprintf | -| new-tests.go:26:26:26:30 | &... | new-tests.go:35:12:35:58 | call to Sprintf | +| new-tests.go:26:26:26:30 | &... | new-tests.go:31:48:31:56 | selection of word | +| new-tests.go:26:26:26:30 | &... | new-tests.go:32:48:32:56 | selection of safe | +| new-tests.go:26:26:26:30 | &... | new-tests.go:35:49:35:57 | selection of word | +| new-tests.go:31:48:31:56 | selection of word | new-tests.go:31:11:31:57 | call to Sprintf | +| new-tests.go:32:48:32:56 | selection of safe | new-tests.go:32:11:32:57 | call to Sprintf | +| new-tests.go:35:49:35:57 | selection of word | new-tests.go:35:12:35:58 | call to Sprintf | | new-tests.go:39:18:39:30 | call to Param | new-tests.go:47:11:47:46 | ...+... | | new-tests.go:49:18:49:30 | call to Query | new-tests.go:50:11:50:46 | ...+... | | new-tests.go:62:2:62:39 | ... := ...[0] | new-tests.go:63:17:63:23 | reqBody | | new-tests.go:62:31:62:38 | selection of Body | new-tests.go:62:2:62:39 | ... := ...[0] | | new-tests.go:63:17:63:23 | reqBody | new-tests.go:63:26:63:30 | &... | -| new-tests.go:63:26:63:30 | &... | new-tests.go:68:11:68:57 | call to Sprintf | -| new-tests.go:63:26:63:30 | &... | new-tests.go:69:11:69:57 | call to Sprintf | -| new-tests.go:63:26:63:30 | &... | new-tests.go:74:12:74:58 | call to Sprintf | +| new-tests.go:63:26:63:30 | &... | new-tests.go:68:48:68:56 | selection of word | +| new-tests.go:63:26:63:30 | &... | new-tests.go:69:48:69:56 | selection of safe | +| new-tests.go:63:26:63:30 | &... | new-tests.go:74:49:74:57 | selection of word | +| new-tests.go:68:48:68:56 | selection of word | new-tests.go:68:11:68:57 | call to Sprintf | +| new-tests.go:69:48:69:56 | selection of safe | new-tests.go:69:11:69:57 | call to Sprintf | +| new-tests.go:74:49:74:57 | selection of word | new-tests.go:74:12:74:58 | call to Sprintf | | new-tests.go:78:18:78:24 | selection of URL | new-tests.go:78:18:78:32 | call to Query | | new-tests.go:78:18:78:32 | call to Query | new-tests.go:78:18:78:46 | call to Get | | new-tests.go:78:18:78:46 | call to Get | new-tests.go:79:11:79:46 | ...+... | @@ -36,8 +42,11 @@ nodes | builtin.go:132:38:132:51 | untrustedInput | semmle.label | untrustedInput | | new-tests.go:26:26:26:30 | &... | semmle.label | &... | | new-tests.go:31:11:31:57 | call to Sprintf | semmle.label | call to Sprintf | +| new-tests.go:31:48:31:56 | selection of word | semmle.label | selection of word | | new-tests.go:32:11:32:57 | call to Sprintf | semmle.label | call to Sprintf | +| new-tests.go:32:48:32:56 | selection of safe | semmle.label | selection of safe | | new-tests.go:35:12:35:58 | call to Sprintf | semmle.label | call to Sprintf | +| new-tests.go:35:49:35:57 | selection of word | semmle.label | selection of word | | new-tests.go:39:18:39:30 | call to Param | semmle.label | call to Param | | new-tests.go:47:11:47:46 | ...+... | semmle.label | ...+... | | new-tests.go:49:18:49:30 | call to Query | semmle.label | call to Query | @@ -47,8 +56,11 @@ nodes | new-tests.go:63:17:63:23 | reqBody | semmle.label | reqBody | | new-tests.go:63:26:63:30 | &... | semmle.label | &... | | new-tests.go:68:11:68:57 | call to Sprintf | semmle.label | call to Sprintf | +| new-tests.go:68:48:68:56 | selection of word | semmle.label | selection of word | | new-tests.go:69:11:69:57 | call to Sprintf | semmle.label | call to Sprintf | +| new-tests.go:69:48:69:56 | selection of safe | semmle.label | selection of safe | | new-tests.go:74:12:74:58 | call to Sprintf | semmle.label | call to Sprintf | +| new-tests.go:74:49:74:57 | selection of word | semmle.label | selection of word | | new-tests.go:78:18:78:24 | selection of URL | semmle.label | selection of URL | | new-tests.go:78:18:78:32 | call to Query | semmle.label | call to Query | | new-tests.go:78:18:78:46 | call to Get | semmle.label | call to Get | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Beego/ReflectedXss.expected b/go/ql/test/library-tests/semmle/go/frameworks/Beego/ReflectedXss.expected index 2d29d2b2357..29b131c367a 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Beego/ReflectedXss.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Beego/ReflectedXss.expected @@ -47,7 +47,7 @@ edges | test.go:240:15:240:36 | call to GetString | test.go:243:21:243:29 | untrusted | | test.go:253:23:253:44 | call to GetCookie | test.go:253:16:253:45 | type conversion | | test.go:264:62:264:83 | call to GetCookie | test.go:264:55:264:84 | type conversion | -| test.go:269:2:269:40 | ... := ...[0] | test.go:277:21:277:61 | call to GetDisplayString | +| test.go:269:2:269:40 | ... := ...[0] | test.go:277:44:277:60 | selection of Filename | | test.go:269:2:269:40 | ... := ...[0] | test.go:278:38:278:49 | genericFiles | | test.go:269:2:269:40 | ... := ...[0] | test.go:279:37:279:48 | genericFiles | | test.go:269:2:269:40 | ... := ...[0] | test.go:285:4:285:15 | genericFiles | @@ -61,6 +61,7 @@ edges | test.go:269:2:269:40 | ... := ...[0] | test.go:295:39:295:50 | genericFiles | | test.go:269:2:269:40 | ... := ...[0] | test.go:296:40:296:51 | genericFiles | | test.go:269:2:269:40 | ... := ...[0] | test.go:297:39:297:50 | genericFiles | +| test.go:277:44:277:60 | selection of Filename | test.go:277:21:277:61 | call to GetDisplayString | | test.go:278:21:278:53 | call to SliceChunk | test.go:278:21:278:92 | selection of Filename | | test.go:278:38:278:49 | genericFiles | test.go:278:21:278:53 | call to SliceChunk | | test.go:279:21:279:60 | call to SliceDiff | test.go:279:21:279:96 | selection of Filename | @@ -177,6 +178,7 @@ nodes | test.go:264:62:264:83 | call to GetCookie | semmle.label | call to GetCookie | | test.go:269:2:269:40 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:277:21:277:61 | call to GetDisplayString | semmle.label | call to GetDisplayString | +| test.go:277:44:277:60 | selection of Filename | semmle.label | selection of Filename | | test.go:278:21:278:53 | call to SliceChunk | semmle.label | call to SliceChunk | | test.go:278:21:278:92 | selection of Filename | semmle.label | selection of Filename | | test.go:278:38:278:49 | genericFiles | semmle.label | genericFiles | diff --git a/go/ql/test/query-tests/Security/CWE-022/TaintedPath.expected b/go/ql/test/query-tests/Security/CWE-022/TaintedPath.expected index 2e7a965b514..307906f7e9b 100644 --- a/go/ql/test/query-tests/Security/CWE-022/TaintedPath.expected +++ b/go/ql/test/query-tests/Security/CWE-022/TaintedPath.expected @@ -1,13 +1,15 @@ edges | TaintedPath.go:13:18:13:22 | selection of URL | TaintedPath.go:13:18:13:30 | call to Query | | TaintedPath.go:13:18:13:30 | call to Query | TaintedPath.go:16:29:16:40 | tainted_path | -| TaintedPath.go:13:18:13:30 | call to Query | TaintedPath.go:20:28:20:69 | call to Join | +| TaintedPath.go:13:18:13:30 | call to Query | TaintedPath.go:20:57:20:68 | tainted_path | +| TaintedPath.go:20:57:20:68 | tainted_path | TaintedPath.go:20:28:20:69 | call to Join | | tst.go:14:2:14:39 | ... := ...[1] | tst.go:17:41:17:56 | selection of Filename | nodes | TaintedPath.go:13:18:13:22 | selection of URL | semmle.label | selection of URL | | TaintedPath.go:13:18:13:30 | call to Query | semmle.label | call to Query | | TaintedPath.go:16:29:16:40 | tainted_path | semmle.label | tainted_path | | TaintedPath.go:20:28:20:69 | call to Join | semmle.label | call to Join | +| TaintedPath.go:20:57:20:68 | tainted_path | semmle.label | tainted_path | | tst.go:14:2:14:39 | ... := ...[1] | semmle.label | ... := ...[1] | | tst.go:17:41:17:56 | selection of Filename | semmle.label | selection of Filename | subpaths diff --git a/go/ql/test/query-tests/Security/CWE-022/ZipSlip.expected b/go/ql/test/query-tests/Security/CWE-022/ZipSlip.expected index 1c3a46096c2..f10f103c963 100644 --- a/go/ql/test/query-tests/Security/CWE-022/ZipSlip.expected +++ b/go/ql/test/query-tests/Security/CWE-022/ZipSlip.expected @@ -1,5 +1,6 @@ edges -| UnsafeUnzipSymlinkGood.go:52:24:52:32 | definition of candidate | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | +| UnsafeUnzipSymlinkGood.go:52:24:52:32 | definition of candidate | UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | +| UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | | UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | | UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | | UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | UnsafeUnzipSymlinkGood.go:52:24:52:32 | definition of candidate | @@ -13,6 +14,7 @@ edges nodes | UnsafeUnzipSymlinkGood.go:52:24:52:32 | definition of candidate | semmle.label | definition of candidate | | UnsafeUnzipSymlinkGood.go:61:31:61:62 | call to Join | semmle.label | call to Join | +| UnsafeUnzipSymlinkGood.go:61:53:61:61 | candidate | semmle.label | candidate | | UnsafeUnzipSymlinkGood.go:72:3:72:25 | ... := ...[0] | semmle.label | ... := ...[0] | | UnsafeUnzipSymlinkGood.go:76:24:76:38 | selection of Linkname | semmle.label | selection of Linkname | | UnsafeUnzipSymlinkGood.go:76:70:76:80 | selection of Name | semmle.label | selection of Name | diff --git a/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index cfc49180bba..19c94698899 100644 --- a/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -11,25 +11,47 @@ edges | GitSubcommands.go:10:13:10:27 | call to Query | GitSubcommands.go:16:36:16:42 | tainted | | SanitizingDoubleDash.go:9:13:9:19 | selection of URL | SanitizingDoubleDash.go:9:13:9:27 | call to Query | | SanitizingDoubleDash.go:9:13:9:27 | call to Query | SanitizingDoubleDash.go:14:23:14:33 | slice expression | -| SanitizingDoubleDash.go:9:13:9:27 | call to Query | SanitizingDoubleDash.go:40:23:40:30 | arrayLit | -| SanitizingDoubleDash.go:9:13:9:27 | call to Query | SanitizingDoubleDash.go:54:23:54:30 | arrayLit | -| SanitizingDoubleDash.go:9:13:9:27 | call to Query | SanitizingDoubleDash.go:70:23:70:30 | arrayLit | +| SanitizingDoubleDash.go:9:13:9:27 | call to Query | SanitizingDoubleDash.go:39:31:39:37 | tainted | +| SanitizingDoubleDash.go:9:13:9:27 | call to Query | SanitizingDoubleDash.go:53:21:53:28 | arrayLit | +| SanitizingDoubleDash.go:9:13:9:27 | call to Query | SanitizingDoubleDash.go:68:31:68:37 | tainted | | SanitizingDoubleDash.go:9:13:9:27 | call to Query | SanitizingDoubleDash.go:80:23:80:29 | tainted | +| SanitizingDoubleDash.go:39:14:39:44 | call to append | SanitizingDoubleDash.go:40:23:40:30 | arrayLit | +| SanitizingDoubleDash.go:39:31:39:37 | tainted | SanitizingDoubleDash.go:39:14:39:44 | call to append | +| SanitizingDoubleDash.go:53:14:53:35 | call to append | SanitizingDoubleDash.go:54:23:54:30 | arrayLit | +| SanitizingDoubleDash.go:53:21:53:28 | arrayLit | SanitizingDoubleDash.go:53:14:53:35 | call to append | +| SanitizingDoubleDash.go:68:14:68:38 | call to append | SanitizingDoubleDash.go:69:21:69:28 | arrayLit | +| SanitizingDoubleDash.go:68:31:68:37 | tainted | SanitizingDoubleDash.go:68:14:68:38 | call to append | +| SanitizingDoubleDash.go:69:14:69:35 | call to append | SanitizingDoubleDash.go:70:23:70:30 | arrayLit | +| SanitizingDoubleDash.go:69:21:69:28 | arrayLit | SanitizingDoubleDash.go:69:14:69:35 | call to append | | SanitizingDoubleDash.go:92:13:92:19 | selection of URL | SanitizingDoubleDash.go:92:13:92:27 | call to Query | | SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:96:24:96:34 | slice expression | | SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:101:24:101:34 | slice expression | | SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:105:30:105:36 | tainted | | SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:106:24:106:31 | arrayLit | -| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:112:24:112:31 | arrayLit | -| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:118:24:118:31 | arrayLit | -| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:124:24:124:31 | arrayLit | -| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:130:24:130:31 | arrayLit | -| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:137:24:137:31 | arrayLit | -| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:144:24:144:31 | arrayLit | +| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:111:37:111:43 | tainted | +| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:117:31:117:37 | tainted | +| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:123:31:123:37 | tainted | +| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:129:21:129:28 | arrayLit | +| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:136:31:136:37 | tainted | +| SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:142:31:142:37 | tainted | | SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:148:30:148:36 | tainted | | SanitizingDoubleDash.go:92:13:92:27 | call to Query | SanitizingDoubleDash.go:152:24:152:30 | tainted | | SanitizingDoubleDash.go:105:15:105:37 | slice literal [array] | SanitizingDoubleDash.go:106:24:106:31 | arrayLit | | SanitizingDoubleDash.go:105:30:105:36 | tainted | SanitizingDoubleDash.go:105:15:105:37 | slice literal [array] | +| SanitizingDoubleDash.go:111:14:111:44 | call to append | SanitizingDoubleDash.go:112:24:112:31 | arrayLit | +| SanitizingDoubleDash.go:111:37:111:43 | tainted | SanitizingDoubleDash.go:111:14:111:44 | call to append | +| SanitizingDoubleDash.go:117:14:117:44 | call to append | SanitizingDoubleDash.go:118:24:118:31 | arrayLit | +| SanitizingDoubleDash.go:117:31:117:37 | tainted | SanitizingDoubleDash.go:117:14:117:44 | call to append | +| SanitizingDoubleDash.go:123:14:123:38 | call to append | SanitizingDoubleDash.go:124:24:124:31 | arrayLit | +| SanitizingDoubleDash.go:123:31:123:37 | tainted | SanitizingDoubleDash.go:123:14:123:38 | call to append | +| SanitizingDoubleDash.go:129:14:129:35 | call to append | SanitizingDoubleDash.go:130:24:130:31 | arrayLit | +| SanitizingDoubleDash.go:129:21:129:28 | arrayLit | SanitizingDoubleDash.go:129:14:129:35 | call to append | +| SanitizingDoubleDash.go:136:14:136:38 | call to append | SanitizingDoubleDash.go:137:24:137:31 | arrayLit | +| SanitizingDoubleDash.go:136:31:136:37 | tainted | SanitizingDoubleDash.go:136:14:136:38 | call to append | +| SanitizingDoubleDash.go:142:14:142:38 | call to append | SanitizingDoubleDash.go:143:21:143:28 | arrayLit | +| SanitizingDoubleDash.go:142:31:142:37 | tainted | SanitizingDoubleDash.go:142:14:142:38 | call to append | +| SanitizingDoubleDash.go:143:14:143:35 | call to append | SanitizingDoubleDash.go:144:24:144:31 | arrayLit | +| SanitizingDoubleDash.go:143:21:143:28 | arrayLit | SanitizingDoubleDash.go:143:14:143:35 | call to append | nodes | ArgumentInjection.go:9:10:9:16 | selection of URL | semmle.label | selection of URL | | ArgumentInjection.go:9:10:9:24 | call to Query | semmle.label | call to Query | @@ -47,8 +69,16 @@ nodes | SanitizingDoubleDash.go:9:13:9:19 | selection of URL | semmle.label | selection of URL | | SanitizingDoubleDash.go:9:13:9:27 | call to Query | semmle.label | call to Query | | SanitizingDoubleDash.go:14:23:14:33 | slice expression | semmle.label | slice expression | +| SanitizingDoubleDash.go:39:14:39:44 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:39:31:39:37 | tainted | semmle.label | tainted | | SanitizingDoubleDash.go:40:23:40:30 | arrayLit | semmle.label | arrayLit | +| SanitizingDoubleDash.go:53:14:53:35 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:53:21:53:28 | arrayLit | semmle.label | arrayLit | | SanitizingDoubleDash.go:54:23:54:30 | arrayLit | semmle.label | arrayLit | +| SanitizingDoubleDash.go:68:14:68:38 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:68:31:68:37 | tainted | semmle.label | tainted | +| SanitizingDoubleDash.go:69:14:69:35 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:69:21:69:28 | arrayLit | semmle.label | arrayLit | | SanitizingDoubleDash.go:70:23:70:30 | arrayLit | semmle.label | arrayLit | | SanitizingDoubleDash.go:80:23:80:29 | tainted | semmle.label | tainted | | SanitizingDoubleDash.go:92:13:92:19 | selection of URL | semmle.label | selection of URL | @@ -58,11 +88,25 @@ nodes | SanitizingDoubleDash.go:105:15:105:37 | slice literal [array] | semmle.label | slice literal [array] | | SanitizingDoubleDash.go:105:30:105:36 | tainted | semmle.label | tainted | | SanitizingDoubleDash.go:106:24:106:31 | arrayLit | semmle.label | arrayLit | +| SanitizingDoubleDash.go:111:14:111:44 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:111:37:111:43 | tainted | semmle.label | tainted | | SanitizingDoubleDash.go:112:24:112:31 | arrayLit | semmle.label | arrayLit | +| SanitizingDoubleDash.go:117:14:117:44 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:117:31:117:37 | tainted | semmle.label | tainted | | SanitizingDoubleDash.go:118:24:118:31 | arrayLit | semmle.label | arrayLit | +| SanitizingDoubleDash.go:123:14:123:38 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:123:31:123:37 | tainted | semmle.label | tainted | | SanitizingDoubleDash.go:124:24:124:31 | arrayLit | semmle.label | arrayLit | +| SanitizingDoubleDash.go:129:14:129:35 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:129:21:129:28 | arrayLit | semmle.label | arrayLit | | SanitizingDoubleDash.go:130:24:130:31 | arrayLit | semmle.label | arrayLit | +| SanitizingDoubleDash.go:136:14:136:38 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:136:31:136:37 | tainted | semmle.label | tainted | | SanitizingDoubleDash.go:137:24:137:31 | arrayLit | semmle.label | arrayLit | +| SanitizingDoubleDash.go:142:14:142:38 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:142:31:142:37 | tainted | semmle.label | tainted | +| SanitizingDoubleDash.go:143:14:143:35 | call to append | semmle.label | call to append | +| SanitizingDoubleDash.go:143:21:143:28 | arrayLit | semmle.label | arrayLit | | SanitizingDoubleDash.go:144:24:144:31 | arrayLit | semmle.label | arrayLit | | SanitizingDoubleDash.go:148:30:148:36 | tainted | semmle.label | tainted | | SanitizingDoubleDash.go:152:24:152:30 | tainted | semmle.label | tainted | diff --git a/go/ql/test/query-tests/Security/CWE-078/StoredCommand.expected b/go/ql/test/query-tests/Security/CWE-078/StoredCommand.expected index ea667480966..e0e028fff91 100644 --- a/go/ql/test/query-tests/Security/CWE-078/StoredCommand.expected +++ b/go/ql/test/query-tests/Security/CWE-078/StoredCommand.expected @@ -1,7 +1,12 @@ edges -| StoredCommand.go:11:2:11:27 | ... := ...[0] | StoredCommand.go:14:22:14:28 | cmdName | +| StoredCommand.go:11:2:11:27 | ... := ...[0] | StoredCommand.go:13:2:13:5 | rows | +| StoredCommand.go:13:2:13:5 | rows | StoredCommand.go:13:12:13:19 | &... | +| StoredCommand.go:13:12:13:19 | &... | StoredCommand.go:13:12:13:19 | &... | +| StoredCommand.go:13:12:13:19 | &... | StoredCommand.go:14:22:14:28 | cmdName | nodes | StoredCommand.go:11:2:11:27 | ... := ...[0] | semmle.label | ... := ...[0] | +| StoredCommand.go:13:2:13:5 | rows | semmle.label | rows | +| StoredCommand.go:13:12:13:19 | &... | semmle.label | &... | | StoredCommand.go:14:22:14:28 | cmdName | semmle.label | cmdName | subpaths #select diff --git a/go/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected b/go/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected index 4f3ee95ffe8..31a8d097158 100644 --- a/go/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected +++ b/go/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected @@ -9,19 +9,27 @@ edges | contenttype.go:73:10:73:28 | call to FormValue | contenttype.go:79:11:79:14 | data | | contenttype.go:88:10:88:28 | call to FormValue | contenttype.go:91:4:91:7 | data | | contenttype.go:113:10:113:28 | call to FormValue | contenttype.go:114:50:114:53 | data | -| reflectedxsstest.go:27:2:27:38 | ... := ...[0] | reflectedxsstest.go:28:10:28:57 | type conversion | +| reflectedxsstest.go:27:2:27:38 | ... := ...[0] | reflectedxsstest.go:28:50:28:55 | cookie | +| reflectedxsstest.go:28:17:28:56 | call to Sprintf | reflectedxsstest.go:28:10:28:57 | type conversion | +| reflectedxsstest.go:28:50:28:55 | cookie | reflectedxsstest.go:28:17:28:56 | call to Sprintf | | reflectedxsstest.go:31:2:31:44 | ... := ...[0] | reflectedxsstest.go:32:34:32:37 | file | -| reflectedxsstest.go:31:2:31:44 | ... := ...[1] | reflectedxsstest.go:34:10:34:62 | type conversion | -| reflectedxsstest.go:32:2:32:38 | ... := ...[0] | reflectedxsstest.go:33:10:33:57 | type conversion | +| reflectedxsstest.go:31:2:31:44 | ... := ...[1] | reflectedxsstest.go:34:46:34:60 | selection of Filename | +| reflectedxsstest.go:32:2:32:38 | ... := ...[0] | reflectedxsstest.go:33:49:33:55 | content | | reflectedxsstest.go:32:34:32:37 | file | reflectedxsstest.go:32:2:32:38 | ... := ...[0] | +| reflectedxsstest.go:33:17:33:56 | call to Sprintf | reflectedxsstest.go:33:10:33:57 | type conversion | +| reflectedxsstest.go:33:49:33:55 | content | reflectedxsstest.go:33:17:33:56 | call to Sprintf | +| reflectedxsstest.go:34:17:34:61 | call to Sprintf | reflectedxsstest.go:34:10:34:62 | type conversion | +| reflectedxsstest.go:34:46:34:60 | selection of Filename | reflectedxsstest.go:34:17:34:61 | call to Sprintf | | reflectedxsstest.go:38:2:38:35 | ... := ...[0] | reflectedxsstest.go:39:16:39:21 | reader | | reflectedxsstest.go:39:2:39:32 | ... := ...[0] | reflectedxsstest.go:40:14:40:17 | part | | reflectedxsstest.go:39:2:39:32 | ... := ...[0] | reflectedxsstest.go:42:2:42:5 | part | | reflectedxsstest.go:39:16:39:21 | reader | reflectedxsstest.go:39:2:39:32 | ... := ...[0] | | reflectedxsstest.go:40:14:40:17 | part | reflectedxsstest.go:40:14:40:28 | call to FileName | -| reflectedxsstest.go:40:14:40:28 | call to FileName | reflectedxsstest.go:44:10:44:55 | type conversion | +| reflectedxsstest.go:40:14:40:28 | call to FileName | reflectedxsstest.go:44:46:44:53 | partName | | reflectedxsstest.go:41:2:41:10 | definition of byteSlice | reflectedxsstest.go:45:10:45:18 | byteSlice | | reflectedxsstest.go:42:2:42:5 | part | reflectedxsstest.go:41:2:41:10 | definition of byteSlice | +| reflectedxsstest.go:44:17:44:54 | call to Sprintf | reflectedxsstest.go:44:10:44:55 | type conversion | +| reflectedxsstest.go:44:46:44:53 | partName | reflectedxsstest.go:44:17:44:54 | call to Sprintf | | reflectedxsstest.go:51:14:51:18 | selection of URL | reflectedxsstest.go:51:14:51:26 | call to Query | | reflectedxsstest.go:51:14:51:26 | call to Query | reflectedxsstest.go:54:11:54:21 | type conversion | | tst.go:14:15:14:20 | selection of Form | tst.go:14:15:14:36 | call to Get | @@ -56,12 +64,18 @@ nodes | contenttype.go:114:50:114:53 | data | semmle.label | data | | reflectedxsstest.go:27:2:27:38 | ... := ...[0] | semmle.label | ... := ...[0] | | reflectedxsstest.go:28:10:28:57 | type conversion | semmle.label | type conversion | +| reflectedxsstest.go:28:17:28:56 | call to Sprintf | semmle.label | call to Sprintf | +| reflectedxsstest.go:28:50:28:55 | cookie | semmle.label | cookie | | reflectedxsstest.go:31:2:31:44 | ... := ...[0] | semmle.label | ... := ...[0] | | reflectedxsstest.go:31:2:31:44 | ... := ...[1] | semmle.label | ... := ...[1] | | reflectedxsstest.go:32:2:32:38 | ... := ...[0] | semmle.label | ... := ...[0] | | reflectedxsstest.go:32:34:32:37 | file | semmle.label | file | | reflectedxsstest.go:33:10:33:57 | type conversion | semmle.label | type conversion | +| reflectedxsstest.go:33:17:33:56 | call to Sprintf | semmle.label | call to Sprintf | +| reflectedxsstest.go:33:49:33:55 | content | semmle.label | content | | reflectedxsstest.go:34:10:34:62 | type conversion | semmle.label | type conversion | +| reflectedxsstest.go:34:17:34:61 | call to Sprintf | semmle.label | call to Sprintf | +| reflectedxsstest.go:34:46:34:60 | selection of Filename | semmle.label | selection of Filename | | reflectedxsstest.go:38:2:38:35 | ... := ...[0] | semmle.label | ... := ...[0] | | reflectedxsstest.go:39:2:39:32 | ... := ...[0] | semmle.label | ... := ...[0] | | reflectedxsstest.go:39:16:39:21 | reader | semmle.label | reader | @@ -70,6 +84,8 @@ nodes | reflectedxsstest.go:41:2:41:10 | definition of byteSlice | semmle.label | definition of byteSlice | | reflectedxsstest.go:42:2:42:5 | part | semmle.label | part | | reflectedxsstest.go:44:10:44:55 | type conversion | semmle.label | type conversion | +| reflectedxsstest.go:44:17:44:54 | call to Sprintf | semmle.label | call to Sprintf | +| reflectedxsstest.go:44:46:44:53 | partName | semmle.label | partName | | reflectedxsstest.go:45:10:45:18 | byteSlice | semmle.label | byteSlice | | reflectedxsstest.go:51:14:51:18 | selection of URL | semmle.label | selection of URL | | reflectedxsstest.go:51:14:51:26 | call to Query | semmle.label | call to Query | diff --git a/go/ql/test/query-tests/Security/CWE-079/StoredXss.expected b/go/ql/test/query-tests/Security/CWE-079/StoredXss.expected index 1e513a5d4a9..f51eda4c93c 100644 --- a/go/ql/test/query-tests/Security/CWE-079/StoredXss.expected +++ b/go/ql/test/query-tests/Security/CWE-079/StoredXss.expected @@ -1,11 +1,16 @@ edges | StoredXss.go:13:21:13:31 | call to Name | StoredXss.go:13:21:13:36 | ...+... | -| stored.go:18:3:18:28 | ... := ...[0] | stored.go:30:22:30:25 | name | +| stored.go:18:3:18:28 | ... := ...[0] | stored.go:25:14:25:17 | rows | +| stored.go:25:14:25:17 | rows | stored.go:25:29:25:33 | &... | +| stored.go:25:29:25:33 | &... | stored.go:25:29:25:33 | &... | +| stored.go:25:29:25:33 | &... | stored.go:30:22:30:25 | name | | stored.go:59:30:59:33 | definition of path | stored.go:61:22:61:25 | path | nodes | StoredXss.go:13:21:13:31 | call to Name | semmle.label | call to Name | | StoredXss.go:13:21:13:36 | ...+... | semmle.label | ...+... | | stored.go:18:3:18:28 | ... := ...[0] | semmle.label | ... := ...[0] | +| stored.go:25:14:25:17 | rows | semmle.label | rows | +| stored.go:25:29:25:33 | &... | semmle.label | &... | | stored.go:30:22:30:25 | name | semmle.label | name | | stored.go:59:30:59:33 | definition of path | semmle.label | definition of path | | stored.go:61:22:61:25 | path | semmle.label | path | diff --git a/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected b/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected index 93d447e40ab..c1ded7d69f8 100644 --- a/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected +++ b/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected @@ -1,21 +1,30 @@ edges +| SqlInjection.go:10:7:11:30 | call to Sprintf | SqlInjection.go:12:11:12:11 | q | | SqlInjection.go:11:3:11:9 | selection of URL | SqlInjection.go:11:3:11:17 | call to Query | -| SqlInjection.go:11:3:11:17 | call to Query | SqlInjection.go:12:11:12:11 | q | +| SqlInjection.go:11:3:11:17 | call to Query | SqlInjection.go:11:3:11:29 | index expression | +| SqlInjection.go:11:3:11:29 | index expression | SqlInjection.go:10:7:11:30 | call to Sprintf | | issue48.go:17:2:17:33 | ... := ...[0] | issue48.go:18:17:18:17 | b | | issue48.go:17:25:17:32 | selection of Body | issue48.go:17:2:17:33 | ... := ...[0] | | issue48.go:18:17:18:17 | b | issue48.go:18:20:18:39 | &... | -| issue48.go:18:20:18:39 | &... | issue48.go:22:11:22:12 | q3 | +| issue48.go:18:20:18:39 | &... | issue48.go:21:3:21:33 | index expression | +| issue48.go:20:8:21:34 | call to Sprintf | issue48.go:22:11:22:12 | q3 | +| issue48.go:21:3:21:33 | index expression | issue48.go:20:8:21:34 | call to Sprintf | | issue48.go:27:2:27:34 | ... := ...[0] | issue48.go:28:17:28:18 | b2 | | issue48.go:27:26:27:33 | selection of Body | issue48.go:27:2:27:34 | ... := ...[0] | | issue48.go:28:17:28:18 | b2 | issue48.go:28:21:28:41 | &... | -| issue48.go:28:21:28:41 | &... | issue48.go:32:11:32:12 | q4 | +| issue48.go:28:21:28:41 | &... | issue48.go:31:3:31:31 | selection of Category | +| issue48.go:30:8:31:32 | call to Sprintf | issue48.go:32:11:32:12 | q4 | +| issue48.go:31:3:31:31 | selection of Category | issue48.go:30:8:31:32 | call to Sprintf | | issue48.go:37:17:37:50 | type conversion | issue48.go:37:53:37:73 | &... | | issue48.go:37:24:37:30 | selection of URL | issue48.go:37:24:37:38 | call to Query | | issue48.go:37:24:37:38 | call to Query | issue48.go:37:17:37:50 | type conversion | -| issue48.go:37:53:37:73 | &... | issue48.go:41:11:41:12 | q5 | +| issue48.go:37:53:37:73 | &... | issue48.go:40:3:40:31 | selection of Category | +| issue48.go:39:8:40:32 | call to Sprintf | issue48.go:41:11:41:12 | q5 | +| issue48.go:40:3:40:31 | selection of Category | issue48.go:39:8:40:32 | call to Sprintf | | main.go:10:11:10:16 | selection of Form | main.go:10:11:10:28 | index expression | | main.go:14:63:14:67 | selection of URL | main.go:14:63:14:75 | call to Query | -| main.go:14:63:14:75 | call to Query | main.go:14:11:14:84 | call to Sprintf | +| main.go:14:63:14:75 | call to Query | main.go:14:63:14:83 | index expression | +| main.go:14:63:14:83 | index expression | main.go:14:11:14:84 | call to Sprintf | | main.go:15:63:15:70 | selection of Header | main.go:15:63:15:84 | call to Get | | main.go:15:63:15:84 | call to Get | main.go:15:11:15:85 | call to Sprintf | | main.go:27:17:30:2 | &... [pointer, Category] | main.go:33:3:33:13 | RequestData [pointer, Category] | @@ -23,9 +32,10 @@ edges | main.go:29:13:29:19 | selection of URL | main.go:29:13:29:27 | call to Query | | main.go:29:13:29:27 | call to Query | main.go:29:13:29:39 | index expression | | main.go:29:13:29:39 | index expression | main.go:27:18:30:2 | struct literal [Category] | +| main.go:32:7:33:23 | call to Sprintf | main.go:34:11:34:11 | q | | main.go:33:3:33:13 | RequestData [pointer, Category] | main.go:33:3:33:13 | implicit dereference [Category] | | main.go:33:3:33:13 | implicit dereference [Category] | main.go:33:3:33:22 | selection of Category | -| main.go:33:3:33:22 | selection of Category | main.go:34:11:34:11 | q | +| main.go:33:3:33:22 | selection of Category | main.go:32:7:33:23 | call to Sprintf | | main.go:38:2:38:12 | definition of RequestData [pointer, Category] | main.go:39:2:39:12 | RequestData [pointer, Category] | | main.go:38:2:38:12 | definition of RequestData [pointer, Category] | main.go:42:3:42:13 | RequestData [pointer, Category] | | main.go:39:2:39:12 | RequestData [pointer, Category] | main.go:39:2:39:12 | implicit dereference [Category] | @@ -33,9 +43,10 @@ edges | main.go:39:25:39:31 | selection of URL | main.go:39:25:39:39 | call to Query | | main.go:39:25:39:39 | call to Query | main.go:39:25:39:51 | index expression | | main.go:39:25:39:51 | index expression | main.go:39:2:39:12 | implicit dereference [Category] | +| main.go:41:7:42:23 | call to Sprintf | main.go:43:11:43:11 | q | | main.go:42:3:42:13 | RequestData [pointer, Category] | main.go:42:3:42:13 | implicit dereference [Category] | | main.go:42:3:42:13 | implicit dereference [Category] | main.go:42:3:42:22 | selection of Category | -| main.go:42:3:42:22 | selection of Category | main.go:43:11:43:11 | q | +| main.go:42:3:42:22 | selection of Category | main.go:41:7:42:23 | call to Sprintf | | main.go:47:2:47:12 | definition of RequestData [pointer, Category] | main.go:48:4:48:14 | RequestData [pointer, Category] | | main.go:47:2:47:12 | definition of RequestData [pointer, Category] | main.go:51:3:51:13 | RequestData [pointer, Category] | | main.go:48:3:48:14 | star expression [Category] | main.go:47:2:47:12 | definition of RequestData [pointer, Category] | @@ -43,9 +54,10 @@ edges | main.go:48:28:48:34 | selection of URL | main.go:48:28:48:42 | call to Query | | main.go:48:28:48:42 | call to Query | main.go:48:28:48:54 | index expression | | main.go:48:28:48:54 | index expression | main.go:48:3:48:14 | star expression [Category] | +| main.go:50:7:51:23 | call to Sprintf | main.go:52:11:52:11 | q | | main.go:51:3:51:13 | RequestData [pointer, Category] | main.go:51:3:51:13 | implicit dereference [Category] | | main.go:51:3:51:13 | implicit dereference [Category] | main.go:51:3:51:22 | selection of Category | -| main.go:51:3:51:22 | selection of Category | main.go:52:11:52:11 | q | +| main.go:51:3:51:22 | selection of Category | main.go:50:7:51:23 | call to Sprintf | | main.go:56:2:56:12 | definition of RequestData [pointer, Category] | main.go:57:4:57:14 | RequestData [pointer, Category] | | main.go:56:2:56:12 | definition of RequestData [pointer, Category] | main.go:60:5:60:15 | RequestData [pointer, Category] | | main.go:57:3:57:14 | star expression [Category] | main.go:56:2:56:12 | definition of RequestData [pointer, Category] | @@ -53,7 +65,8 @@ edges | main.go:57:28:57:34 | selection of URL | main.go:57:28:57:42 | call to Query | | main.go:57:28:57:42 | call to Query | main.go:57:28:57:54 | index expression | | main.go:57:28:57:54 | index expression | main.go:57:3:57:14 | star expression [Category] | -| main.go:60:3:60:25 | selection of Category | main.go:61:11:61:11 | q | +| main.go:59:7:60:26 | call to Sprintf | main.go:61:11:61:11 | q | +| main.go:60:3:60:25 | selection of Category | main.go:59:7:60:26 | call to Sprintf | | main.go:60:4:60:15 | star expression [Category] | main.go:60:3:60:25 | selection of Category | | main.go:60:5:60:15 | RequestData [pointer, Category] | main.go:60:4:60:15 | star expression [Category] | | mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:57:22:57:29 | pipeline | @@ -71,29 +84,38 @@ edges | mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:80:22:80:27 | filter | | mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:81:18:81:25 | pipeline | nodes +| SqlInjection.go:10:7:11:30 | call to Sprintf | semmle.label | call to Sprintf | | SqlInjection.go:11:3:11:9 | selection of URL | semmle.label | selection of URL | | SqlInjection.go:11:3:11:17 | call to Query | semmle.label | call to Query | +| SqlInjection.go:11:3:11:29 | index expression | semmle.label | index expression | | SqlInjection.go:12:11:12:11 | q | semmle.label | q | | issue48.go:17:2:17:33 | ... := ...[0] | semmle.label | ... := ...[0] | | issue48.go:17:25:17:32 | selection of Body | semmle.label | selection of Body | | issue48.go:18:17:18:17 | b | semmle.label | b | | issue48.go:18:20:18:39 | &... | semmle.label | &... | +| issue48.go:20:8:21:34 | call to Sprintf | semmle.label | call to Sprintf | +| issue48.go:21:3:21:33 | index expression | semmle.label | index expression | | issue48.go:22:11:22:12 | q3 | semmle.label | q3 | | issue48.go:27:2:27:34 | ... := ...[0] | semmle.label | ... := ...[0] | | issue48.go:27:26:27:33 | selection of Body | semmle.label | selection of Body | | issue48.go:28:17:28:18 | b2 | semmle.label | b2 | | issue48.go:28:21:28:41 | &... | semmle.label | &... | +| issue48.go:30:8:31:32 | call to Sprintf | semmle.label | call to Sprintf | +| issue48.go:31:3:31:31 | selection of Category | semmle.label | selection of Category | | issue48.go:32:11:32:12 | q4 | semmle.label | q4 | | issue48.go:37:17:37:50 | type conversion | semmle.label | type conversion | | issue48.go:37:24:37:30 | selection of URL | semmle.label | selection of URL | | issue48.go:37:24:37:38 | call to Query | semmle.label | call to Query | | issue48.go:37:53:37:73 | &... | semmle.label | &... | +| issue48.go:39:8:40:32 | call to Sprintf | semmle.label | call to Sprintf | +| issue48.go:40:3:40:31 | selection of Category | semmle.label | selection of Category | | issue48.go:41:11:41:12 | q5 | semmle.label | q5 | | main.go:10:11:10:16 | selection of Form | semmle.label | selection of Form | | main.go:10:11:10:28 | index expression | semmle.label | index expression | | main.go:14:11:14:84 | call to Sprintf | semmle.label | call to Sprintf | | main.go:14:63:14:67 | selection of URL | semmle.label | selection of URL | | main.go:14:63:14:75 | call to Query | semmle.label | call to Query | +| main.go:14:63:14:83 | index expression | semmle.label | index expression | | main.go:15:11:15:85 | call to Sprintf | semmle.label | call to Sprintf | | main.go:15:63:15:70 | selection of Header | semmle.label | selection of Header | | main.go:15:63:15:84 | call to Get | semmle.label | call to Get | @@ -102,6 +124,7 @@ nodes | main.go:29:13:29:19 | selection of URL | semmle.label | selection of URL | | main.go:29:13:29:27 | call to Query | semmle.label | call to Query | | main.go:29:13:29:39 | index expression | semmle.label | index expression | +| main.go:32:7:33:23 | call to Sprintf | semmle.label | call to Sprintf | | main.go:33:3:33:13 | RequestData [pointer, Category] | semmle.label | RequestData [pointer, Category] | | main.go:33:3:33:13 | implicit dereference [Category] | semmle.label | implicit dereference [Category] | | main.go:33:3:33:22 | selection of Category | semmle.label | selection of Category | @@ -112,6 +135,7 @@ nodes | main.go:39:25:39:31 | selection of URL | semmle.label | selection of URL | | main.go:39:25:39:39 | call to Query | semmle.label | call to Query | | main.go:39:25:39:51 | index expression | semmle.label | index expression | +| main.go:41:7:42:23 | call to Sprintf | semmle.label | call to Sprintf | | main.go:42:3:42:13 | RequestData [pointer, Category] | semmle.label | RequestData [pointer, Category] | | main.go:42:3:42:13 | implicit dereference [Category] | semmle.label | implicit dereference [Category] | | main.go:42:3:42:22 | selection of Category | semmle.label | selection of Category | @@ -122,6 +146,7 @@ nodes | main.go:48:28:48:34 | selection of URL | semmle.label | selection of URL | | main.go:48:28:48:42 | call to Query | semmle.label | call to Query | | main.go:48:28:48:54 | index expression | semmle.label | index expression | +| main.go:50:7:51:23 | call to Sprintf | semmle.label | call to Sprintf | | main.go:51:3:51:13 | RequestData [pointer, Category] | semmle.label | RequestData [pointer, Category] | | main.go:51:3:51:13 | implicit dereference [Category] | semmle.label | implicit dereference [Category] | | main.go:51:3:51:22 | selection of Category | semmle.label | selection of Category | @@ -132,6 +157,7 @@ nodes | main.go:57:28:57:34 | selection of URL | semmle.label | selection of URL | | main.go:57:28:57:42 | call to Query | semmle.label | call to Query | | main.go:57:28:57:54 | index expression | semmle.label | index expression | +| main.go:59:7:60:26 | call to Sprintf | semmle.label | call to Sprintf | | main.go:60:3:60:25 | selection of Category | semmle.label | selection of Category | | main.go:60:4:60:15 | star expression [Category] | semmle.label | star expression [Category] | | main.go:60:5:60:15 | RequestData [pointer, Category] | semmle.label | RequestData [pointer, Category] | diff --git a/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.expected b/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.expected index ba37534511a..e47a4768465 100644 --- a/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.expected +++ b/go/ql/test/query-tests/Security/CWE-327/UnsafeTLS.expected @@ -14,9 +14,18 @@ edges | UnsafeTLS.go:305:5:305:47 | selection of TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | UnsafeTLS.go:304:18:306:4 | slice literal | | UnsafeTLS.go:313:5:313:45 | selection of TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | UnsafeTLS.go:312:18:314:4 | slice literal | | UnsafeTLS.go:329:53:329:93 | selection of TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | UnsafeTLS.go:329:25:329:94 | call to append | -| UnsafeTLS.go:334:13:334:38 | call to InsecureCipherSuites | UnsafeTLS.go:336:26:336:58 | call to append | -| UnsafeTLS.go:342:13:342:38 | call to InsecureCipherSuites | UnsafeTLS.go:346:25:346:36 | cipherSuites | -| UnsafeTLS.go:351:13:351:38 | call to InsecureCipherSuites | UnsafeTLS.go:355:25:355:36 | cipherSuites | +| UnsafeTLS.go:334:13:334:38 | call to InsecureCipherSuites | UnsafeTLS.go:336:54:336:57 | selection of ID | +| UnsafeTLS.go:336:54:336:57 | selection of ID | UnsafeTLS.go:336:26:336:58 | call to append | +| UnsafeTLS.go:342:13:342:38 | call to InsecureCipherSuites | UnsafeTLS.go:344:40:344:43 | selection of ID | +| UnsafeTLS.go:344:19:344:44 | call to append | UnsafeTLS.go:344:26:344:37 | cipherSuites | +| UnsafeTLS.go:344:19:344:44 | call to append | UnsafeTLS.go:346:25:346:36 | cipherSuites | +| UnsafeTLS.go:344:26:344:37 | cipherSuites | UnsafeTLS.go:344:19:344:44 | call to append | +| UnsafeTLS.go:344:40:344:43 | selection of ID | UnsafeTLS.go:344:19:344:44 | call to append | +| UnsafeTLS.go:351:13:351:38 | call to InsecureCipherSuites | UnsafeTLS.go:353:40:353:51 | selection of ID | +| UnsafeTLS.go:353:19:353:52 | call to append | UnsafeTLS.go:353:26:353:37 | cipherSuites | +| UnsafeTLS.go:353:19:353:52 | call to append | UnsafeTLS.go:355:25:355:36 | cipherSuites | +| UnsafeTLS.go:353:26:353:37 | cipherSuites | UnsafeTLS.go:353:19:353:52 | call to append | +| UnsafeTLS.go:353:40:353:51 | selection of ID | UnsafeTLS.go:353:19:353:52 | call to append | | UnsafeTLS.go:363:5:363:47 | selection of TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | UnsafeTLS.go:362:18:364:4 | slice literal | | UnsafeTLS.go:371:5:371:47 | selection of TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | UnsafeTLS.go:370:18:372:4 | slice literal | | UnsafeTLS.go:379:5:379:47 | selection of TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | UnsafeTLS.go:378:18:380:4 | slice literal | @@ -94,9 +103,16 @@ nodes | UnsafeTLS.go:329:53:329:93 | selection of TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | semmle.label | selection of TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | | UnsafeTLS.go:334:13:334:38 | call to InsecureCipherSuites | semmle.label | call to InsecureCipherSuites | | UnsafeTLS.go:336:26:336:58 | call to append | semmle.label | call to append | +| UnsafeTLS.go:336:54:336:57 | selection of ID | semmle.label | selection of ID | | UnsafeTLS.go:342:13:342:38 | call to InsecureCipherSuites | semmle.label | call to InsecureCipherSuites | +| UnsafeTLS.go:344:19:344:44 | call to append | semmle.label | call to append | +| UnsafeTLS.go:344:26:344:37 | cipherSuites | semmle.label | cipherSuites | +| UnsafeTLS.go:344:40:344:43 | selection of ID | semmle.label | selection of ID | | UnsafeTLS.go:346:25:346:36 | cipherSuites | semmle.label | cipherSuites | | UnsafeTLS.go:351:13:351:38 | call to InsecureCipherSuites | semmle.label | call to InsecureCipherSuites | +| UnsafeTLS.go:353:19:353:52 | call to append | semmle.label | call to append | +| UnsafeTLS.go:353:26:353:37 | cipherSuites | semmle.label | cipherSuites | +| UnsafeTLS.go:353:40:353:51 | selection of ID | semmle.label | selection of ID | | UnsafeTLS.go:355:25:355:36 | cipherSuites | semmle.label | cipherSuites | | UnsafeTLS.go:362:18:364:4 | slice literal | semmle.label | slice literal | | UnsafeTLS.go:363:5:363:47 | selection of TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | semmle.label | selection of TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | diff --git a/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.expected b/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.expected index 59af6f28787..e1e037af120 100644 --- a/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.expected +++ b/go/ql/test/query-tests/Security/CWE-338/InsecureRandomness/InsecureRandomness.expected @@ -1,6 +1,8 @@ edges -| sample.go:15:24:15:63 | type conversion | sample.go:16:9:16:15 | slice expression | -| sample.go:15:49:15:61 | call to Uint32 | sample.go:15:24:15:63 | type conversion | +| sample.go:15:10:15:64 | call to Sum256 | sample.go:16:9:16:15 | slice expression | +| sample.go:15:24:15:63 | type conversion | sample.go:15:10:15:64 | call to Sum256 | +| sample.go:15:31:15:62 | call to Sprintf | sample.go:15:24:15:63 | type conversion | +| sample.go:15:49:15:61 | call to Uint32 | sample.go:15:31:15:62 | call to Sprintf | | sample.go:16:9:16:15 | slice expression | sample.go:26:25:26:30 | call to Guid | | sample.go:33:2:33:6 | definition of nonce | sample.go:37:25:37:29 | nonce | | sample.go:33:2:33:6 | definition of nonce | sample.go:37:32:37:36 | nonce | @@ -8,7 +10,9 @@ edges | sample.go:35:14:35:19 | random | sample.go:33:2:33:6 | definition of nonce | nodes | InsecureRandomness.go:12:18:12:40 | call to Intn | semmle.label | call to Intn | +| sample.go:15:10:15:64 | call to Sum256 | semmle.label | call to Sum256 | | sample.go:15:24:15:63 | type conversion | semmle.label | type conversion | +| sample.go:15:31:15:62 | call to Sprintf | semmle.label | call to Sprintf | | sample.go:15:49:15:61 | call to Uint32 | semmle.label | call to Uint32 | | sample.go:16:9:16:15 | slice expression | semmle.label | slice expression | | sample.go:26:25:26:30 | call to Guid | semmle.label | call to Guid | diff --git a/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.expected b/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.expected index c21e28717c7..35b84bf249a 100644 --- a/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.expected +++ b/go/ql/test/query-tests/Security/CWE-352/ConstantOauth2State.expected @@ -17,7 +17,8 @@ edges | ConstantOauth2State.go:210:9:210:42 | call to AuthCodeURL | ConstantOauth2State.go:211:54:211:56 | url | | ConstantOauth2State.go:232:9:232:42 | call to AuthCodeURL | ConstantOauth2State.go:233:28:233:30 | url | | ConstantOauth2State.go:239:17:239:39 | "http://localhost:8080" | ConstantOauth2State.go:249:9:249:12 | conf | -| ConstantOauth2State.go:256:38:256:60 | "http://localhost:8080" | ConstantOauth2State.go:266:9:266:12 | conf | +| ConstantOauth2State.go:256:17:256:67 | call to Sprintf | ConstantOauth2State.go:266:9:266:12 | conf | +| ConstantOauth2State.go:256:38:256:60 | "http://localhost:8080" | ConstantOauth2State.go:256:17:256:67 | call to Sprintf | | ConstantOauth2State.go:272:17:272:21 | "oob" | ConstantOauth2State.go:282:9:282:12 | conf | nodes | ConstantOauth2State.go:20:26:20:32 | "state" | semmle.label | "state" | @@ -46,6 +47,7 @@ nodes | ConstantOauth2State.go:239:17:239:39 | "http://localhost:8080" | semmle.label | "http://localhost:8080" | | ConstantOauth2State.go:249:9:249:12 | conf | semmle.label | conf | | ConstantOauth2State.go:249:26:249:41 | stateStringConst | semmle.label | stateStringConst | +| ConstantOauth2State.go:256:17:256:67 | call to Sprintf | semmle.label | call to Sprintf | | ConstantOauth2State.go:256:38:256:60 | "http://localhost:8080" | semmle.label | "http://localhost:8080" | | ConstantOauth2State.go:266:9:266:12 | conf | semmle.label | conf | | ConstantOauth2State.go:266:26:266:41 | stateStringConst | semmle.label | stateStringConst | From 47d0a6d2e3bf36b6124162e1c21867ad65161791 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 20 Jun 2023 14:30:43 +0200 Subject: [PATCH 223/364] Python: Restore rest of experimental files --- .../experimental/Security/CWE-074/JinjaBad.py | 19 +++++++++ .../Security/CWE-074/JinjaGood.py | 20 ++++++++++ .../semmle/python/templates/Airspeed.py | 10 +++++ .../templates/AirspeedSSTISinks.expected | 2 + .../python/templates/AirspeedSSTISinks.ql | 5 +++ .../semmle/python/templates/Bottle.py | 17 ++++++++ .../python/templates/BottleSSTISinks.expected | 3 ++ .../python/templates/BottleSSTISinks.ql | 5 +++ .../semmle/python/templates/Chameleon.py | 5 +++ .../templates/ChameleonSSTISinks.expected | 2 + .../python/templates/ChameleonSSTISinks.ql | 5 +++ .../templates/CheetahSSTISinks.expected | 3 ++ .../python/templates/CheetahSSTISinks.ql | 5 +++ .../semmle/python/templates/CheetahSinks.py | 20 ++++++++++ .../templates/ChevronSSTISinks.expected | 2 + .../python/templates/ChevronSSTISinks.ql | 5 +++ .../semmle/python/templates/ChevronSinks.py | 22 +++++++++++ .../python/templates/DjangoSSTISinks.expected | 2 + .../python/templates/DjangoSSTISinks.ql | 5 +++ .../python/templates/DjangoTemplates.py | 39 +++++++++++++++++++ .../semmle/python/templates/Genshi.py | 10 +++++ .../python/templates/GenshiSSTISinks.expected | 3 ++ .../python/templates/GenshiSSTISinks.ql | 5 +++ .../python/templates/Jinja2Templates.py | 17 ++++++++ .../python/templates/JinjaSSTISinks.expected | 4 ++ .../semmle/python/templates/JinjaSSTISinks.ql | 5 +++ .../semmle/python/templates/Mako.py | 5 +++ .../python/templates/MakoSSTISinks.expected | 2 + .../semmle/python/templates/MakoSSTISinks.ql | 5 +++ .../semmle/python/templates/TRender.py | 6 +++ .../templates/TRenderSSTISinks.expected | 2 + .../python/templates/TRenderSSTISinks.ql | 5 +++ .../semmle/python/templates/options | 1 + 33 files changed, 266 insertions(+) create mode 100644 python/ql/src/experimental/Security/CWE-074/JinjaBad.py create mode 100644 python/ql/src/experimental/Security/CWE-074/JinjaGood.py create mode 100644 python/ql/test/experimental/semmle/python/templates/Airspeed.py create mode 100644 python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/Bottle.py create mode 100644 python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/Chameleon.py create mode 100644 python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/CheetahSinks.py create mode 100644 python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/ChevronSinks.py create mode 100644 python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/DjangoTemplates.py create mode 100644 python/ql/test/experimental/semmle/python/templates/Genshi.py create mode 100644 python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/Jinja2Templates.py create mode 100644 python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/Mako.py create mode 100644 python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/TRender.py create mode 100644 python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.expected create mode 100644 python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.ql create mode 100644 python/ql/test/experimental/semmle/python/templates/options diff --git a/python/ql/src/experimental/Security/CWE-074/JinjaBad.py b/python/ql/src/experimental/Security/CWE-074/JinjaBad.py new file mode 100644 index 00000000000..aaac3ec819e --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-074/JinjaBad.py @@ -0,0 +1,19 @@ +from django.urls import path +from django.http import HttpResponse +from jinja2 import Template as Jinja2_Template +from jinja2 import Environment, DictLoader, escape + + +def a(request): + # Load the template + template = request.GET['template'] + t = Jinja2_Template(template) + name = request.GET['name'] + # Render the template with the context data + html = t.render(name=escape(name)) + return HttpResponse(html) + + +urlpatterns = [ + path('a', a), +] diff --git a/python/ql/src/experimental/Security/CWE-074/JinjaGood.py b/python/ql/src/experimental/Security/CWE-074/JinjaGood.py new file mode 100644 index 00000000000..a1b60561850 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-074/JinjaGood.py @@ -0,0 +1,20 @@ +from django.urls import path +from django.http import HttpResponse +from jinja2 import Template as Jinja2_Template +from jinja2 import Environment, DictLoader, escape + + +def a(request): + # Load the template + template = request.GET['template'] + env = SandboxedEnvironment(undefined=StrictUndefined) + t = env.from_string(template) + name = request.GET['name'] + # Render the template with the context data + html = t.render(name=escape(name)) + return HttpResponse(html) + + +urlpatterns = [ + path('a', a), +] diff --git a/python/ql/test/experimental/semmle/python/templates/Airspeed.py b/python/ql/test/experimental/semmle/python/templates/Airspeed.py new file mode 100644 index 00000000000..a41d70432a0 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/Airspeed.py @@ -0,0 +1,10 @@ +from bottle import Bottle, route, request, redirect, response +import airspeed + + +app = Bottle() + + +@route('/other') +def a(): + return airspeed.Template("sink") diff --git a/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.expected new file mode 100644 index 00000000000..e938211434c --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.expected @@ -0,0 +1,2 @@ +WARNING: Type SSTISink has been deprecated and may be removed in future (AirspeedSSTISinks.ql:4,6-14) +| Airspeed.py:10:30:10:35 | argument to airspeed.Template() | diff --git a/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.ql new file mode 100644 index 00000000000..e9c51ef11ad --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/AirspeedSSTISinks.ql @@ -0,0 +1,5 @@ +import python +import experimental.semmle.python.templates.Airspeed + +from SSTISink s +select s diff --git a/python/ql/test/experimental/semmle/python/templates/Bottle.py b/python/ql/test/experimental/semmle/python/templates/Bottle.py new file mode 100644 index 00000000000..f6b2fec090e --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/Bottle.py @@ -0,0 +1,17 @@ +from bottle import Bottle, route, request, redirect, response, SimpleTemplate +from bottle import template as temp + + +app = Bottle() + + +@route('/other') +def a(): + template = "test" + tpl = SimpleTemplate(template) + + +@route('/other2') +def b(): + template = "test" + return temp(template, name='World') diff --git a/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.expected new file mode 100644 index 00000000000..1802708c2de --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.expected @@ -0,0 +1,3 @@ +WARNING: Type SSTISink has been deprecated and may be removed in future (BottleSSTISinks.ql:4,6-14) +| Bottle.py:11:26:11:33 | argument to bottle.SimpleTemplate() | +| Bottle.py:17:17:17:24 | argument to bottle.template() | diff --git a/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.ql new file mode 100644 index 00000000000..c0ba59ef957 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/BottleSSTISinks.ql @@ -0,0 +1,5 @@ +import python +import experimental.semmle.python.templates.Bottle + +from SSTISink s +select s diff --git a/python/ql/test/experimental/semmle/python/templates/Chameleon.py b/python/ql/test/experimental/semmle/python/templates/Chameleon.py new file mode 100644 index 00000000000..6d96f0752a9 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/Chameleon.py @@ -0,0 +1,5 @@ +from chameleon import PageTemplate + + +def chameleon(): + template = PageTemplate("sink") diff --git a/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.expected new file mode 100644 index 00000000000..d6a46986f11 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.expected @@ -0,0 +1,2 @@ +WARNING: Type SSTISink has been deprecated and may be removed in future (ChameleonSSTISinks.ql:4,6-14) +| Chameleon.py:5:29:5:34 | argument to Chameleon.PageTemplate() | diff --git a/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.ql new file mode 100644 index 00000000000..ee9d41434af --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/ChameleonSSTISinks.ql @@ -0,0 +1,5 @@ +import python +import experimental.semmle.python.templates.Chameleon + +from SSTISink s +select s diff --git a/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.expected new file mode 100644 index 00000000000..3971b25e356 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.expected @@ -0,0 +1,3 @@ +WARNING: Type SSTISink has been deprecated and may be removed in future (CheetahSSTISinks.ql:4,6-14) +| CheetahSinks.py:10:21:10:26 | argument to Cheetah.Template.Template() | +| CheetahSinks.py:20:20:20:25 | argument to Cheetah.Template.Template() | diff --git a/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.ql new file mode 100644 index 00000000000..10c6c79a4d5 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/CheetahSSTISinks.ql @@ -0,0 +1,5 @@ +import python +import experimental.semmle.python.templates.Cheetah + +from SSTISink s +select s diff --git a/python/ql/test/experimental/semmle/python/templates/CheetahSinks.py b/python/ql/test/experimental/semmle/python/templates/CheetahSinks.py new file mode 100644 index 00000000000..0bb3364a178 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/CheetahSinks.py @@ -0,0 +1,20 @@ +from bottle import Bottle, route, request, redirect, response, SimpleTemplate +from Cheetah.Template import Template + + +app = Bottle() + + +@route('/other') +def a(): + return Template("sink") + + +class Template3(Template): + title = 'Hello World Example!' + contents = 'Hello World!' + + +@route('/other2') +def b(): + t3 = Template3("sink") diff --git a/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.expected new file mode 100644 index 00000000000..50ebb008209 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.expected @@ -0,0 +1,2 @@ +WARNING: Type SSTISink has been deprecated and may be removed in future (ChevronSSTISinks.ql:4,6-14) +| ChevronSinks.py:10:27:10:32 | argument to chevron.render() | diff --git a/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.ql new file mode 100644 index 00000000000..545c1f8f79a --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/ChevronSSTISinks.ql @@ -0,0 +1,5 @@ +import python +import experimental.semmle.python.templates.Chevron + +from SSTISink s +select s diff --git a/python/ql/test/experimental/semmle/python/templates/ChevronSinks.py b/python/ql/test/experimental/semmle/python/templates/ChevronSinks.py new file mode 100644 index 00000000000..26d35708bb6 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/ChevronSinks.py @@ -0,0 +1,22 @@ +from bottle import Bottle, route, request, redirect, response, SimpleTemplate +import chevron + + +app = Bottle() + + +@route('/other') +def a(): + return chevron.render("sink", {"key": "value"}) + + +@route('/other2') +def b(): + sink = { + 'template': "template", + + 'data': { + 'key': 'value' + } + } + return chevron.render(**sink) diff --git a/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.expected new file mode 100644 index 00000000000..a38fdbc323f --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.expected @@ -0,0 +1,2 @@ +WARNING: Type SSTISink has been deprecated and may be removed in future (DjangoSSTISinks.ql:4,6-14) +| DjangoTemplates.py:9:18:9:25 | argument to Django.template() | diff --git a/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.ql new file mode 100644 index 00000000000..eecd31aeb87 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/DjangoSSTISinks.ql @@ -0,0 +1,5 @@ +import python +import experimental.semmle.python.templates.DjangoTemplate + +from SSTISink s +select s diff --git a/python/ql/test/experimental/semmle/python/templates/DjangoTemplates.py b/python/ql/test/experimental/semmle/python/templates/DjangoTemplates.py new file mode 100644 index 00000000000..981109bf7dc --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/DjangoTemplates.py @@ -0,0 +1,39 @@ +from django.urls import path +from django.http import HttpResponse +from django.template import Template, Context, Engine, engines + + +def dj(request): + # Load the template + template = request.GET['template'] + t = Template(template) + ctx = Context(locals()) + html = t.render(ctx) + return HttpResponse(html) + + +def djEngine(request): + # Load the template + template = request.GET['template'] + + django_engine = engines['django'] + t = django_engine.from_string(template) + ctx = Context(locals()) + html = t.render(ctx) + return HttpResponse(html) + + +def djEngineJinja(request): + # Load the template + template = request.GET['template'] + + django_engine = engines['jinja'] + t = django_engine.from_string(template) + ctx = Context(locals()) + html = t.render(ctx) + return HttpResponse(html) + + +urlpatterns = [ + path('', dj) +] diff --git a/python/ql/test/experimental/semmle/python/templates/Genshi.py b/python/ql/test/experimental/semmle/python/templates/Genshi.py new file mode 100644 index 00000000000..7c46a2b31dc --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/Genshi.py @@ -0,0 +1,10 @@ + + +def genshi1(): + from genshi.template import MarkupTemplate + tmpl = MarkupTemplate('sink') + + +def genshi2(): + from genshi.template import TextTemplate + tmpl = TextTemplate('sink') \ No newline at end of file diff --git a/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.expected new file mode 100644 index 00000000000..cfc22364413 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.expected @@ -0,0 +1,3 @@ +WARNING: Type SSTISink has been deprecated and may be removed in future (GenshiSSTISinks.ql:4,6-14) +| Genshi.py:5:27:5:32 | argument to genshi.template.MarkupTemplate() | +| Genshi.py:10:25:10:30 | argument to genshi.template.TextTemplate() | diff --git a/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.ql new file mode 100644 index 00000000000..f0d87e97ec1 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/GenshiSSTISinks.ql @@ -0,0 +1,5 @@ +import python +import experimental.semmle.python.templates.Genshi + +from SSTISink s +select s diff --git a/python/ql/test/experimental/semmle/python/templates/Jinja2Templates.py b/python/ql/test/experimental/semmle/python/templates/Jinja2Templates.py new file mode 100644 index 00000000000..e52538d4946 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/Jinja2Templates.py @@ -0,0 +1,17 @@ +from jinja2 import Template as Jinja2_Template +from jinja2 import Environment, DictLoader, escape + + +def jinja(): + t = Jinja2_Template("sink") + + +def jinja2(): + random = "esdad" + "asdad" + t = Jinja2_Template(random) + + +def jinja3(): + random = 1234 + t = Jinja2_Template("sink"+random) + diff --git a/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.expected new file mode 100644 index 00000000000..7b91c934947 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.expected @@ -0,0 +1,4 @@ +WARNING: Type SSTISink has been deprecated and may be removed in future (JinjaSSTISinks.ql:4,6-14) +| Jinja2Templates.py:6:25:6:30 | argument to jinja2.Template() | +| Jinja2Templates.py:11:25:11:30 | argument to jinja2.Template() | +| Jinja2Templates.py:16:25:16:37 | argument to jinja2.Template() | diff --git a/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.ql new file mode 100644 index 00000000000..ca80d8bc570 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/JinjaSSTISinks.ql @@ -0,0 +1,5 @@ +import python +import experimental.semmle.python.templates.Jinja + +from SSTISink s +select s diff --git a/python/ql/test/experimental/semmle/python/templates/Mako.py b/python/ql/test/experimental/semmle/python/templates/Mako.py new file mode 100644 index 00000000000..3af60b164ea --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/Mako.py @@ -0,0 +1,5 @@ + + +def mako(): + from mako.template import Template + mytemplate = Template("sink") diff --git a/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.expected new file mode 100644 index 00000000000..005e14f218a --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.expected @@ -0,0 +1,2 @@ +WARNING: Type SSTISink has been deprecated and may be removed in future (MakoSSTISinks.ql:4,6-14) +| Mako.py:5:27:5:32 | argument to mako.template.Template() | diff --git a/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.ql new file mode 100644 index 00000000000..eed89420c54 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/MakoSSTISinks.ql @@ -0,0 +1,5 @@ +import python +import experimental.semmle.python.templates.Mako + +from SSTISink s +select s diff --git a/python/ql/test/experimental/semmle/python/templates/TRender.py b/python/ql/test/experimental/semmle/python/templates/TRender.py new file mode 100644 index 00000000000..6ed5a799942 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/TRender.py @@ -0,0 +1,6 @@ + + +def trender(): + from trender import TRender + template = '@greet world!' + compiled = TRender(template) diff --git a/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.expected b/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.expected new file mode 100644 index 00000000000..26dea55a6c8 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.expected @@ -0,0 +1,2 @@ +WARNING: Type SSTISink has been deprecated and may be removed in future (TRenderSSTISinks.ql:4,6-14) +| TRender.py:6:24:6:31 | argument to trender.TRender() | diff --git a/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.ql b/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.ql new file mode 100644 index 00000000000..ec3a1bba57f --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/TRenderSSTISinks.ql @@ -0,0 +1,5 @@ +import python +import experimental.semmle.python.templates.TRender + +from SSTISink s +select s diff --git a/python/ql/test/experimental/semmle/python/templates/options b/python/ql/test/experimental/semmle/python/templates/options new file mode 100644 index 00000000000..c3bc9413072 --- /dev/null +++ b/python/ql/test/experimental/semmle/python/templates/options @@ -0,0 +1 @@ +semmle-extractor-options: --lang=3 --max-import-depth=3 -p ../../../../../query-tests/Security/lib/ From 41534803e593dd62eede637b21e579f62d77cbb4 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 20 Jun 2023 14:41:45 +0200 Subject: [PATCH 224/364] Refactor to use `QueryDoc` Kudos to @erik-krogh for the suggestion. --- ql/ql/src/queries/style/AndroidIdPrefix.ql | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/ql/ql/src/queries/style/AndroidIdPrefix.ql b/ql/ql/src/queries/style/AndroidIdPrefix.ql index 46071b08784..71068cca05d 100644 --- a/ql/ql/src/queries/style/AndroidIdPrefix.ql +++ b/ql/ql/src/queries/style/AndroidIdPrefix.ql @@ -1,6 +1,6 @@ /** * @name Android query without android @id prefix - * @description Android queries should include the `android` prefix in their `@id`. + * @description Android queries should include the `android/` prefix in their `@id`. * @kind problem * @problem.severity warning * @id ql/android-id-prefix @@ -9,10 +9,7 @@ import ql -string getIdProperty(QLDoc doc) { - result = any(string id | id = doc.getContents().splitAt("@") and id.matches("id %")) -} - +/** Holds if `t` transitively imports an Android module. */ predicate importsAndroidModule(TopLevel t) { exists(Import i | t.getAnImport() = i | i.getImportString().toLowerCase().matches("%android%") @@ -24,9 +21,9 @@ predicate importsAndroidModule(TopLevel t) { ) } -from TopLevel t +from QueryDoc d where - t.getLocation().getFile().getRelativePath().matches("%src/Security/%.ql") and - not getIdProperty(t.getQLDoc()).matches("% java/android/%") and - importsAndroidModule(t) -select t, "This Android query is missing the `android` prefix in its `@id`." + d.getLocation().getFile().getRelativePath().matches("%src/Security/%") and + not d.getQueryId().matches("android/%") and + importsAndroidModule(d.getParent()) +select d, "This Android query is missing the `android/` prefix in its `@id`." From 818c312a5680873b85d3c8069542f261d06d2737 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 20 Jun 2023 14:50:33 +0200 Subject: [PATCH 225/364] Add exception for `java/improper-intent-verification` As suggested by @igfoo. --- ql/ql/src/queries/style/AndroidIdPrefix.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/ql/ql/src/queries/style/AndroidIdPrefix.ql b/ql/ql/src/queries/style/AndroidIdPrefix.ql index 71068cca05d..cb12d008c3e 100644 --- a/ql/ql/src/queries/style/AndroidIdPrefix.ql +++ b/ql/ql/src/queries/style/AndroidIdPrefix.ql @@ -25,5 +25,6 @@ from QueryDoc d where d.getLocation().getFile().getRelativePath().matches("%src/Security/%") and not d.getQueryId().matches("android/%") and + not d.getQueryId() = "improper-intent-verification" and // known badly identified query that sadly we can't fix importsAndroidModule(d.getParent()) select d, "This Android query is missing the `android/` prefix in its `@id`." From 768478103cc4e1b5c44be59c39f39a05a3397cab Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 20 Jun 2023 15:16:37 +0200 Subject: [PATCH 226/364] Add another exception --- ql/ql/src/queries/style/AndroidIdPrefix.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/ql/src/queries/style/AndroidIdPrefix.ql b/ql/ql/src/queries/style/AndroidIdPrefix.ql index cb12d008c3e..eae34e2f899 100644 --- a/ql/ql/src/queries/style/AndroidIdPrefix.ql +++ b/ql/ql/src/queries/style/AndroidIdPrefix.ql @@ -25,6 +25,6 @@ from QueryDoc d where d.getLocation().getFile().getRelativePath().matches("%src/Security/%") and not d.getQueryId().matches("android/%") and - not d.getQueryId() = "improper-intent-verification" and // known badly identified query that sadly we can't fix + not d.getQueryId() = ["improper-intent-verification", "improper-webview-certificate-validation"] and // known badly identified queries that sadly we can't fix importsAndroidModule(d.getParent()) select d, "This Android query is missing the `android/` prefix in its `@id`." From 12c810c63d6c566def7a44ebea3369c43bc8b8c9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 20 Jun 2023 15:23:08 +0200 Subject: [PATCH 227/364] QL: Add tests for `FieldOnlyUsedInCharPred.ql` --- .../FieldOnlyUsedInCharPred.expected | 2 ++ .../FieldOnlyUsedInCharPred.qll | 29 +++++++++++++++++++ .../FieldOnlyUsedInCharPred.qlref | 1 + 3 files changed, 32 insertions(+) create mode 100644 ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.expected create mode 100644 ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qll create mode 100644 ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qlref diff --git a/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.expected b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.expected new file mode 100644 index 00000000000..1da84706eff --- /dev/null +++ b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.expected @@ -0,0 +1,2 @@ +| FieldOnlyUsedInCharPred.qll:2:3:2:12 | FieldDecl | Field is only used in CharPred. | +| FieldOnlyUsedInCharPred.qll:22:3:22:11 | FieldDecl | Field is only used in CharPred. | diff --git a/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qll b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qll new file mode 100644 index 00000000000..edfc8b4576e --- /dev/null +++ b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qll @@ -0,0 +1,29 @@ +class C1 extends int { + int field; // BAD + + C1() { + this = field and + this = 0 + } +} + +class C2 extends C1 { + int field2; // GOOD + + C2() { + this = field2 and + this = 0 + } + + int getField() { result = field2 } +} + +class C3 extends int { + C1 field; // GOOD (overridden) + + C3() { this = field } +} + +class C4 extends C3 { + override C2 field; // GOOD (overriding) +} diff --git a/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qlref b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qlref new file mode 100644 index 00000000000..0e77c6ae6fe --- /dev/null +++ b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.qlref @@ -0,0 +1 @@ +queries/style/FieldOnlyUsedInCharPred.ql From d296256920cf4b4a07575f48270bed7c0170f4ed Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 20 Jun 2023 15:24:09 +0200 Subject: [PATCH 228/364] QL: Exclude overridden fields from `FieldOnlyUsedInCharPred.ql` --- ql/ql/src/queries/style/FieldOnlyUsedInCharPred.ql | 3 ++- .../FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.expected | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ql/ql/src/queries/style/FieldOnlyUsedInCharPred.ql b/ql/ql/src/queries/style/FieldOnlyUsedInCharPred.ql index e1f4810d391..3216cc9a6af 100644 --- a/ql/ql/src/queries/style/FieldOnlyUsedInCharPred.ql +++ b/ql/ql/src/queries/style/FieldOnlyUsedInCharPred.ql @@ -21,5 +21,6 @@ where any(PredicateCall call | call.getEnclosingPredicate() = c.getCharPred() and call.getTarget() instanceof NewTypeBranch ).getAnArgument() and - not f.getVarDecl().overrides(_) + not f.getVarDecl().overrides(_) and + not any(FieldDecl other).getVarDecl().overrides(f.getVarDecl()) select f, "Field is only used in CharPred." diff --git a/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.expected b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.expected index 1da84706eff..f41af0cebaf 100644 --- a/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.expected +++ b/ql/ql/test/queries/style/FieldOnlyUsedInCharPred/FieldOnlyUsedInCharPred.expected @@ -1,2 +1 @@ | FieldOnlyUsedInCharPred.qll:2:3:2:12 | FieldDecl | Field is only used in CharPred. | -| FieldOnlyUsedInCharPred.qll:22:3:22:11 | FieldDecl | Field is only used in CharPred. | From c230c9f79301b90a80c0790ea0861efa8b950712 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 20 Jun 2023 15:30:46 +0200 Subject: [PATCH 229/364] Consider only Java files in importsAndroidModule --- ql/ql/src/queries/style/AndroidIdPrefix.ql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ql/ql/src/queries/style/AndroidIdPrefix.ql b/ql/ql/src/queries/style/AndroidIdPrefix.ql index eae34e2f899..0e6da6f32d2 100644 --- a/ql/ql/src/queries/style/AndroidIdPrefix.ql +++ b/ql/ql/src/queries/style/AndroidIdPrefix.ql @@ -11,6 +11,8 @@ import ql /** Holds if `t` transitively imports an Android module. */ predicate importsAndroidModule(TopLevel t) { + t.getFile() = + any(YAML::QLPack pack | pack.getExtractor() = "java").getADependency*().getAFileInPack() and exists(Import i | t.getAnImport() = i | i.getImportString().toLowerCase().matches("%android%") or From 0baf78f8fa38419044f4c09824b4fe98a927fec9 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 20 Jun 2023 14:33:29 +0100 Subject: [PATCH 230/364] Add change note --- .../lib/change-notes/2023-06-20-function-model-path-nodes.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 go/ql/lib/change-notes/2023-06-20-function-model-path-nodes.md diff --git a/go/ql/lib/change-notes/2023-06-20-function-model-path-nodes.md b/go/ql/lib/change-notes/2023-06-20-function-model-path-nodes.md new file mode 100644 index 00000000000..5c616481326 --- /dev/null +++ b/go/ql/lib/change-notes/2023-06-20-function-model-path-nodes.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* When a result of path query flows through a function modeled using `DataFlow::FunctionModel` or `TaintTracking::FunctionModel`, the path now includes nodes corresponding to the input and output to the function. This brings it in line with functions modeled using Models-as-Data. From 3c60f52a1bc4d0fcce4b7774b3276b829c946069 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Tue, 20 Jun 2023 15:40:41 +0200 Subject: [PATCH 231/364] Update ql/ql/src/queries/style/AndroidIdPrefix.ql Co-authored-by: Erik Krogh Kristensen --- ql/ql/src/queries/style/AndroidIdPrefix.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/ql/src/queries/style/AndroidIdPrefix.ql b/ql/ql/src/queries/style/AndroidIdPrefix.ql index 0e6da6f32d2..88b479cc7d4 100644 --- a/ql/ql/src/queries/style/AndroidIdPrefix.ql +++ b/ql/ql/src/queries/style/AndroidIdPrefix.ql @@ -12,7 +12,7 @@ import ql /** Holds if `t` transitively imports an Android module. */ predicate importsAndroidModule(TopLevel t) { t.getFile() = - any(YAML::QLPack pack | pack.getExtractor() = "java").getADependency*().getAFileInPack() and + any(YAML::QLPack pack | pack.getADependency*().getExtractor() = "java").getAFileInPack() and exists(Import i | t.getAnImport() = i | i.getImportString().toLowerCase().matches("%android%") or From 7aec22c1e4f36bdcc720ae8504109d6ba153a71c Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 20 Jun 2023 14:57:23 +0100 Subject: [PATCH 232/364] Ruby: rack - remove MIME modelling --- ruby/ql/lib/codeql/ruby/frameworks/Rack.qll | 7 +- .../ruby/frameworks/rack/internal/Mime.qll | 1311 ----------------- .../frameworks/rack/Rack.expected | 4 +- .../library-tests/frameworks/rack/Rack.ql | 4 - .../library-tests/frameworks/rack/rack.rb | 2 +- 5 files changed, 5 insertions(+), 1323 deletions(-) delete mode 100644 ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll index 74553476d17..4d9342d8805 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll @@ -7,9 +7,8 @@ */ module Rack { import rack.internal.App - import rack.internal.Mime - import rack.internal.Response::Public as Response +import rack.internal.Response::Public as Response - /** DEPRECATED: Alias for App::AppCandidate */ - deprecated class AppCandidate = App::AppCandidate; +/** DEPRECATED: Alias for App::AppCandidate */ +deprecated class AppCandidate = App::AppCandidate; } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll b/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll deleted file mode 100644 index c7682c25638..00000000000 --- a/ruby/ql/lib/codeql/ruby/frameworks/rack/internal/Mime.qll +++ /dev/null @@ -1,1311 +0,0 @@ -/** - * Provides modeling for the `Mime` component of the `Rack` library. - */ - -private import codeql.ruby.ApiGraphs -private import codeql.ruby.DataFlow - -private predicate mimetypeMatches(string ext, string mimeType) { - ext = ".123" and mimeType = "application/vnd.lotus-1-2-3" - or - ext = ".3dml" and mimeType = "text/vnd.in3d.3dml" - or - ext = ".3g2" and mimeType = "video/3gpp2" - or - ext = ".3gp" and mimeType = "video/3gpp" - or - ext = ".a" and mimeType = "application/octet-stream" - or - ext = ".acc" and mimeType = "application/vnd.americandynamics.acc" - or - ext = ".ace" and mimeType = "application/x-ace-compressed" - or - ext = ".acu" and mimeType = "application/vnd.acucobol" - or - ext = ".aep" and mimeType = "application/vnd.audiograph" - or - ext = ".afp" and mimeType = "application/vnd.ibm.modcap" - or - ext = ".ai" and mimeType = "application/postscript" - or - ext = ".aif" and mimeType = "audio/x-aiff" - or - ext = ".aiff" and mimeType = "audio/x-aiff" - or - ext = ".ami" and mimeType = "application/vnd.amiga.ami" - or - ext = ".apng" and mimeType = "image/apng" - or - ext = ".appcache" and mimeType = "text/cache-manifest" - or - ext = ".apr" and mimeType = "application/vnd.lotus-approach" - or - ext = ".asc" and mimeType = "application/pgp-signature" - or - ext = ".asf" and mimeType = "video/x-ms-asf" - or - ext = ".asm" and mimeType = "text/x-asm" - or - ext = ".aso" and mimeType = "application/vnd.accpac.simply.aso" - or - ext = ".asx" and mimeType = "video/x-ms-asf" - or - ext = ".atc" and mimeType = "application/vnd.acucorp" - or - ext = ".atom" and mimeType = "application/atom+xml" - or - ext = ".atomcat" and mimeType = "application/atomcat+xml" - or - ext = ".atomsvc" and mimeType = "application/atomsvc+xml" - or - ext = ".atx" and mimeType = "application/vnd.antix.game-component" - or - ext = ".au" and mimeType = "audio/basic" - or - ext = ".avi" and mimeType = "video/x-msvideo" - or - ext = ".avif" and mimeType = "image/avif" - or - ext = ".bat" and mimeType = "application/x-msdownload" - or - ext = ".bcpio" and mimeType = "application/x-bcpio" - or - ext = ".bdm" and mimeType = "application/vnd.syncml.dm+wbxml" - or - ext = ".bh2" and mimeType = "application/vnd.fujitsu.oasysprs" - or - ext = ".bin" and mimeType = "application/octet-stream" - or - ext = ".bmi" and mimeType = "application/vnd.bmi" - or - ext = ".bmp" and mimeType = "image/bmp" - or - ext = ".box" and mimeType = "application/vnd.previewsystems.box" - or - ext = ".btif" and mimeType = "image/prs.btif" - or - ext = ".bz" and mimeType = "application/x-bzip" - or - ext = ".bz2" and mimeType = "application/x-bzip2" - or - ext = ".c" and mimeType = "text/x-c" - or - ext = ".c4g" and mimeType = "application/vnd.clonk.c4group" - or - ext = ".cab" and mimeType = "application/vnd.ms-cab-compressed" - or - ext = ".cc" and mimeType = "text/x-c" - or - ext = ".ccxml" and mimeType = "application/ccxml+xml" - or - ext = ".cdbcmsg" and mimeType = "application/vnd.contact.cmsg" - or - ext = ".cdkey" and mimeType = "application/vnd.mediastation.cdkey" - or - ext = ".cdx" and mimeType = "chemical/x-cdx" - or - ext = ".cdxml" and mimeType = "application/vnd.chemdraw+xml" - or - ext = ".cdy" and mimeType = "application/vnd.cinderella" - or - ext = ".cer" and mimeType = "application/pkix-cert" - or - ext = ".cgm" and mimeType = "image/cgm" - or - ext = ".chat" and mimeType = "application/x-chat" - or - ext = ".chm" and mimeType = "application/vnd.ms-htmlhelp" - or - ext = ".chrt" and mimeType = "application/vnd.kde.kchart" - or - ext = ".cif" and mimeType = "chemical/x-cif" - or - ext = ".cii" and mimeType = "application/vnd.anser-web-certificate-issue-initiation" - or - ext = ".cil" and mimeType = "application/vnd.ms-artgalry" - or - ext = ".cla" and mimeType = "application/vnd.claymore" - or - ext = ".class" and mimeType = "application/octet-stream" - or - ext = ".clkk" and mimeType = "application/vnd.crick.clicker.keyboard" - or - ext = ".clkp" and mimeType = "application/vnd.crick.clicker.palette" - or - ext = ".clkt" and mimeType = "application/vnd.crick.clicker.template" - or - ext = ".clkw" and mimeType = "application/vnd.crick.clicker.wordbank" - or - ext = ".clkx" and mimeType = "application/vnd.crick.clicker" - or - ext = ".clp" and mimeType = "application/x-msclip" - or - ext = ".cmc" and mimeType = "application/vnd.cosmocaller" - or - ext = ".cmdf" and mimeType = "chemical/x-cmdf" - or - ext = ".cml" and mimeType = "chemical/x-cml" - or - ext = ".cmp" and mimeType = "application/vnd.yellowriver-custom-menu" - or - ext = ".cmx" and mimeType = "image/x-cmx" - or - ext = ".com" and mimeType = "application/x-msdownload" - or - ext = ".conf" and mimeType = "text/plain" - or - ext = ".cpio" and mimeType = "application/x-cpio" - or - ext = ".cpp" and mimeType = "text/x-c" - or - ext = ".cpt" and mimeType = "application/mac-compactpro" - or - ext = ".crd" and mimeType = "application/x-mscardfile" - or - ext = ".crl" and mimeType = "application/pkix-crl" - or - ext = ".crt" and mimeType = "application/x-x509-ca-cert" - or - ext = ".csh" and mimeType = "application/x-csh" - or - ext = ".csml" and mimeType = "chemical/x-csml" - or - ext = ".csp" and mimeType = "application/vnd.commonspace" - or - ext = ".css" and mimeType = "text/css" - or - ext = ".csv" and mimeType = "text/csv" - or - ext = ".curl" and mimeType = "application/vnd.curl" - or - ext = ".cww" and mimeType = "application/prs.cww" - or - ext = ".cxx" and mimeType = "text/x-c" - or - ext = ".daf" and mimeType = "application/vnd.mobius.daf" - or - ext = ".davmount" and mimeType = "application/davmount+xml" - or - ext = ".dcr" and mimeType = "application/x-director" - or - ext = ".dd2" and mimeType = "application/vnd.oma.dd2+xml" - or - ext = ".ddd" and mimeType = "application/vnd.fujixerox.ddd" - or - ext = ".deb" and mimeType = "application/x-debian-package" - or - ext = ".der" and mimeType = "application/x-x509-ca-cert" - or - ext = ".dfac" and mimeType = "application/vnd.dreamfactory" - or - ext = ".diff" and mimeType = "text/x-diff" - or - ext = ".dis" and mimeType = "application/vnd.mobius.dis" - or - ext = ".djv" and mimeType = "image/vnd.djvu" - or - ext = ".djvu" and mimeType = "image/vnd.djvu" - or - ext = ".dll" and mimeType = "application/x-msdownload" - or - ext = ".dmg" and mimeType = "application/octet-stream" - or - ext = ".dna" and mimeType = "application/vnd.dna" - or - ext = ".doc" and mimeType = "application/msword" - or - ext = ".docm" and mimeType = "application/vnd.ms-word.document.macroEnabled.12" - or - ext = ".docx" and - mimeType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" - or - ext = ".dot" and mimeType = "application/msword" - or - ext = ".dotm" and mimeType = "application/vnd.ms-word.template.macroEnabled.12" - or - ext = ".dotx" and - mimeType = "application/vnd.openxmlformats-officedocument.wordprocessingml.template" - or - ext = ".dp" and mimeType = "application/vnd.osgi.dp" - or - ext = ".dpg" and mimeType = "application/vnd.dpgraph" - or - ext = ".dsc" and mimeType = "text/prs.lines.tag" - or - ext = ".dtd" and mimeType = "application/xml-dtd" - or - ext = ".dts" and mimeType = "audio/vnd.dts" - or - ext = ".dtshd" and mimeType = "audio/vnd.dts.hd" - or - ext = ".dv" and mimeType = "video/x-dv" - or - ext = ".dvi" and mimeType = "application/x-dvi" - or - ext = ".dwf" and mimeType = "model/vnd.dwf" - or - ext = ".dwg" and mimeType = "image/vnd.dwg" - or - ext = ".dxf" and mimeType = "image/vnd.dxf" - or - ext = ".dxp" and mimeType = "application/vnd.spotfire.dxp" - or - ext = ".ear" and mimeType = "application/java-archive" - or - ext = ".ecelp4800" and mimeType = "audio/vnd.nuera.ecelp4800" - or - ext = ".ecelp7470" and mimeType = "audio/vnd.nuera.ecelp7470" - or - ext = ".ecelp9600" and mimeType = "audio/vnd.nuera.ecelp9600" - or - ext = ".ecma" and mimeType = "application/ecmascript" - or - ext = ".edm" and mimeType = "application/vnd.novadigm.edm" - or - ext = ".edx" and mimeType = "application/vnd.novadigm.edx" - or - ext = ".efif" and mimeType = "application/vnd.picsel" - or - ext = ".ei6" and mimeType = "application/vnd.pg.osasli" - or - ext = ".eml" and mimeType = "message/rfc822" - or - ext = ".eol" and mimeType = "audio/vnd.digital-winds" - or - ext = ".eot" and mimeType = "application/vnd.ms-fontobject" - or - ext = ".eps" and mimeType = "application/postscript" - or - ext = ".es3" and mimeType = "application/vnd.eszigno3+xml" - or - ext = ".esf" and mimeType = "application/vnd.epson.esf" - or - ext = ".etx" and mimeType = "text/x-setext" - or - ext = ".exe" and mimeType = "application/x-msdownload" - or - ext = ".ext" and mimeType = "application/vnd.novadigm.ext" - or - ext = ".ez" and mimeType = "application/andrew-inset" - or - ext = ".ez2" and mimeType = "application/vnd.ezpix-album" - or - ext = ".ez3" and mimeType = "application/vnd.ezpix-package" - or - ext = ".f" and mimeType = "text/x-fortran" - or - ext = ".f77" and mimeType = "text/x-fortran" - or - ext = ".f90" and mimeType = "text/x-fortran" - or - ext = ".fbs" and mimeType = "image/vnd.fastbidsheet" - or - ext = ".fdf" and mimeType = "application/vnd.fdf" - or - ext = ".fe_launch" and mimeType = "application/vnd.denovo.fcselayout-link" - or - ext = ".fg5" and mimeType = "application/vnd.fujitsu.oasysgp" - or - ext = ".fli" and mimeType = "video/x-fli" - or - ext = ".flif" and mimeType = "image/flif" - or - ext = ".flo" and mimeType = "application/vnd.micrografx.flo" - or - ext = ".flv" and mimeType = "video/x-flv" - or - ext = ".flw" and mimeType = "application/vnd.kde.kivio" - or - ext = ".flx" and mimeType = "text/vnd.fmi.flexstor" - or - ext = ".fly" and mimeType = "text/vnd.fly" - or - ext = ".fm" and mimeType = "application/vnd.framemaker" - or - ext = ".fnc" and mimeType = "application/vnd.frogans.fnc" - or - ext = ".for" and mimeType = "text/x-fortran" - or - ext = ".fpx" and mimeType = "image/vnd.fpx" - or - ext = ".fsc" and mimeType = "application/vnd.fsc.weblaunch" - or - ext = ".fst" and mimeType = "image/vnd.fst" - or - ext = ".ftc" and mimeType = "application/vnd.fluxtime.clip" - or - ext = ".fti" and mimeType = "application/vnd.anser-web-funds-transfer-initiation" - or - ext = ".fvt" and mimeType = "video/vnd.fvt" - or - ext = ".fzs" and mimeType = "application/vnd.fuzzysheet" - or - ext = ".g3" and mimeType = "image/g3fax" - or - ext = ".gac" and mimeType = "application/vnd.groove-account" - or - ext = ".gdl" and mimeType = "model/vnd.gdl" - or - ext = ".gem" and mimeType = "application/octet-stream" - or - ext = ".gemspec" and mimeType = "text/x-script.ruby" - or - ext = ".ghf" and mimeType = "application/vnd.groove-help" - or - ext = ".gif" and mimeType = "image/gif" - or - ext = ".gim" and mimeType = "application/vnd.groove-identity-message" - or - ext = ".gmx" and mimeType = "application/vnd.gmx" - or - ext = ".gph" and mimeType = "application/vnd.flographit" - or - ext = ".gqf" and mimeType = "application/vnd.grafeq" - or - ext = ".gram" and mimeType = "application/srgs" - or - ext = ".grv" and mimeType = "application/vnd.groove-injector" - or - ext = ".grxml" and mimeType = "application/srgs+xml" - or - ext = ".gtar" and mimeType = "application/x-gtar" - or - ext = ".gtm" and mimeType = "application/vnd.groove-tool-message" - or - ext = ".gtw" and mimeType = "model/vnd.gtw" - or - ext = ".gv" and mimeType = "text/vnd.graphviz" - or - ext = ".gz" and mimeType = "application/x-gzip" - or - ext = ".h" and mimeType = "text/x-c" - or - ext = ".h261" and mimeType = "video/h261" - or - ext = ".h263" and mimeType = "video/h263" - or - ext = ".h264" and mimeType = "video/h264" - or - ext = ".hbci" and mimeType = "application/vnd.hbci" - or - ext = ".hdf" and mimeType = "application/x-hdf" - or - ext = ".heic" and mimeType = "image/heic" - or - ext = ".heics" and mimeType = "image/heic-sequence" - or - ext = ".heif" and mimeType = "image/heif" - or - ext = ".heifs" and mimeType = "image/heif-sequence" - or - ext = ".hh" and mimeType = "text/x-c" - or - ext = ".hlp" and mimeType = "application/winhlp" - or - ext = ".hpgl" and mimeType = "application/vnd.hp-hpgl" - or - ext = ".hpid" and mimeType = "application/vnd.hp-hpid" - or - ext = ".hps" and mimeType = "application/vnd.hp-hps" - or - ext = ".hqx" and mimeType = "application/mac-binhex40" - or - ext = ".htc" and mimeType = "text/x-component" - or - ext = ".htke" and mimeType = "application/vnd.kenameaapp" - or - ext = ".htm" and mimeType = "text/html" - or - ext = ".html" and mimeType = "text/html" - or - ext = ".hvd" and mimeType = "application/vnd.yamaha.hv-dic" - or - ext = ".hvp" and mimeType = "application/vnd.yamaha.hv-voice" - or - ext = ".hvs" and mimeType = "application/vnd.yamaha.hv-script" - or - ext = ".icc" and mimeType = "application/vnd.iccprofile" - or - ext = ".ice" and mimeType = "x-conference/x-cooltalk" - or - ext = ".ico" and mimeType = "image/vnd.microsoft.icon" - or - ext = ".ics" and mimeType = "text/calendar" - or - ext = ".ief" and mimeType = "image/ief" - or - ext = ".ifb" and mimeType = "text/calendar" - or - ext = ".ifm" and mimeType = "application/vnd.shana.informed.formdata" - or - ext = ".igl" and mimeType = "application/vnd.igloader" - or - ext = ".igs" and mimeType = "model/iges" - or - ext = ".igx" and mimeType = "application/vnd.micrografx.igx" - or - ext = ".iif" and mimeType = "application/vnd.shana.informed.interchange" - or - ext = ".imp" and mimeType = "application/vnd.accpac.simply.imp" - or - ext = ".ims" and mimeType = "application/vnd.ms-ims" - or - ext = ".ipk" and mimeType = "application/vnd.shana.informed.package" - or - ext = ".irm" and mimeType = "application/vnd.ibm.rights-management" - or - ext = ".irp" and mimeType = "application/vnd.irepository.package+xml" - or - ext = ".iso" and mimeType = "application/octet-stream" - or - ext = ".itp" and mimeType = "application/vnd.shana.informed.formtemplate" - or - ext = ".ivp" and mimeType = "application/vnd.immervision-ivp" - or - ext = ".ivu" and mimeType = "application/vnd.immervision-ivu" - or - ext = ".jad" and mimeType = "text/vnd.sun.j2me.app-descriptor" - or - ext = ".jam" and mimeType = "application/vnd.jam" - or - ext = ".jar" and mimeType = "application/java-archive" - or - ext = ".java" and mimeType = "text/x-java-source" - or - ext = ".jisp" and mimeType = "application/vnd.jisp" - or - ext = ".jlt" and mimeType = "application/vnd.hp-jlyt" - or - ext = ".jnlp" and mimeType = "application/x-java-jnlp-file" - or - ext = ".joda" and mimeType = "application/vnd.joost.joda-archive" - or - ext = ".jp2" and mimeType = "image/jp2" - or - ext = ".jpeg" and mimeType = "image/jpeg" - or - ext = ".jpg" and mimeType = "image/jpeg" - or - ext = ".jpgv" and mimeType = "video/jpeg" - or - ext = ".jpm" and mimeType = "video/jpm" - or - ext = ".js" and mimeType = "application/javascript" - or - ext = ".json" and mimeType = "application/json" - or - ext = ".karbon" and mimeType = "application/vnd.kde.karbon" - or - ext = ".kfo" and mimeType = "application/vnd.kde.kformula" - or - ext = ".kia" and mimeType = "application/vnd.kidspiration" - or - ext = ".kml" and mimeType = "application/vnd.google-earth.kml+xml" - or - ext = ".kmz" and mimeType = "application/vnd.google-earth.kmz" - or - ext = ".kne" and mimeType = "application/vnd.kinar" - or - ext = ".kon" and mimeType = "application/vnd.kde.kontour" - or - ext = ".kpr" and mimeType = "application/vnd.kde.kpresenter" - or - ext = ".ksp" and mimeType = "application/vnd.kde.kspread" - or - ext = ".ktz" and mimeType = "application/vnd.kahootz" - or - ext = ".kwd" and mimeType = "application/vnd.kde.kword" - or - ext = ".latex" and mimeType = "application/x-latex" - or - ext = ".lbd" and mimeType = "application/vnd.llamagraphics.life-balance.desktop" - or - ext = ".lbe" and mimeType = "application/vnd.llamagraphics.life-balance.exchange+xml" - or - ext = ".les" and mimeType = "application/vnd.hhe.lesson-player" - or - ext = ".link66" and mimeType = "application/vnd.route66.link66+xml" - or - ext = ".log" and mimeType = "text/plain" - or - ext = ".lostxml" and mimeType = "application/lost+xml" - or - ext = ".lrm" and mimeType = "application/vnd.ms-lrm" - or - ext = ".ltf" and mimeType = "application/vnd.frogans.ltf" - or - ext = ".lvp" and mimeType = "audio/vnd.lucent.voice" - or - ext = ".lwp" and mimeType = "application/vnd.lotus-wordpro" - or - ext = ".m3u" and mimeType = "audio/x-mpegurl" - or - ext = ".m3u8" and mimeType = "application/x-mpegurl" - or - ext = ".m4a" and mimeType = "audio/mp4a-latm" - or - ext = ".m4v" and mimeType = "video/mp4" - or - ext = ".ma" and mimeType = "application/mathematica" - or - ext = ".mag" and mimeType = "application/vnd.ecowin.chart" - or - ext = ".man" and mimeType = "text/troff" - or - ext = ".manifest" and mimeType = "text/cache-manifest" - or - ext = ".mathml" and mimeType = "application/mathml+xml" - or - ext = ".mbk" and mimeType = "application/vnd.mobius.mbk" - or - ext = ".mbox" and mimeType = "application/mbox" - or - ext = ".mc1" and mimeType = "application/vnd.medcalcdata" - or - ext = ".mcd" and mimeType = "application/vnd.mcd" - or - ext = ".mdb" and mimeType = "application/x-msaccess" - or - ext = ".mdi" and mimeType = "image/vnd.ms-modi" - or - ext = ".mdoc" and mimeType = "text/troff" - or - ext = ".me" and mimeType = "text/troff" - or - ext = ".mfm" and mimeType = "application/vnd.mfmp" - or - ext = ".mgz" and mimeType = "application/vnd.proteus.magazine" - or - ext = ".mid" and mimeType = "audio/midi" - or - ext = ".midi" and mimeType = "audio/midi" - or - ext = ".mif" and mimeType = "application/vnd.mif" - or - ext = ".mime" and mimeType = "message/rfc822" - or - ext = ".mj2" and mimeType = "video/mj2" - or - ext = ".mlp" and mimeType = "application/vnd.dolby.mlp" - or - ext = ".mmd" and mimeType = "application/vnd.chipnuts.karaoke-mmd" - or - ext = ".mmf" and mimeType = "application/vnd.smaf" - or - ext = ".mml" and mimeType = "application/mathml+xml" - or - ext = ".mmr" and mimeType = "image/vnd.fujixerox.edmics-mmr" - or - ext = ".mng" and mimeType = "video/x-mng" - or - ext = ".mny" and mimeType = "application/x-msmoney" - or - ext = ".mov" and mimeType = "video/quicktime" - or - ext = ".movie" and mimeType = "video/x-sgi-movie" - or - ext = ".mp3" and mimeType = "audio/mpeg" - or - ext = ".mp4" and mimeType = "video/mp4" - or - ext = ".mp4a" and mimeType = "audio/mp4" - or - ext = ".mp4s" and mimeType = "application/mp4" - or - ext = ".mp4v" and mimeType = "video/mp4" - or - ext = ".mpc" and mimeType = "application/vnd.mophun.certificate" - or - ext = ".mpd" and mimeType = "application/dash+xml" - or - ext = ".mpeg" and mimeType = "video/mpeg" - or - ext = ".mpg" and mimeType = "video/mpeg" - or - ext = ".mpga" and mimeType = "audio/mpeg" - or - ext = ".mpkg" and mimeType = "application/vnd.apple.installer+xml" - or - ext = ".mpm" and mimeType = "application/vnd.blueice.multipass" - or - ext = ".mpn" and mimeType = "application/vnd.mophun.application" - or - ext = ".mpp" and mimeType = "application/vnd.ms-project" - or - ext = ".mpy" and mimeType = "application/vnd.ibm.minipay" - or - ext = ".mqy" and mimeType = "application/vnd.mobius.mqy" - or - ext = ".mrc" and mimeType = "application/marc" - or - ext = ".ms" and mimeType = "text/troff" - or - ext = ".mscml" and mimeType = "application/mediaservercontrol+xml" - or - ext = ".mseq" and mimeType = "application/vnd.mseq" - or - ext = ".msf" and mimeType = "application/vnd.epson.msf" - or - ext = ".msh" and mimeType = "model/mesh" - or - ext = ".msi" and mimeType = "application/x-msdownload" - or - ext = ".msl" and mimeType = "application/vnd.mobius.msl" - or - ext = ".msty" and mimeType = "application/vnd.muvee.style" - or - ext = ".mts" and mimeType = "model/vnd.mts" - or - ext = ".mus" and mimeType = "application/vnd.musician" - or - ext = ".mvb" and mimeType = "application/x-msmediaview" - or - ext = ".mwf" and mimeType = "application/vnd.mfer" - or - ext = ".mxf" and mimeType = "application/mxf" - or - ext = ".mxl" and mimeType = "application/vnd.recordare.musicxml" - or - ext = ".mxml" and mimeType = "application/xv+xml" - or - ext = ".mxs" and mimeType = "application/vnd.triscape.mxs" - or - ext = ".mxu" and mimeType = "video/vnd.mpegurl" - or - ext = ".n" and mimeType = "application/vnd.nokia.n-gage.symbian.install" - or - ext = ".nc" and mimeType = "application/x-netcdf" - or - ext = ".ngdat" and mimeType = "application/vnd.nokia.n-gage.data" - or - ext = ".nlu" and mimeType = "application/vnd.neurolanguage.nlu" - or - ext = ".nml" and mimeType = "application/vnd.enliven" - or - ext = ".nnd" and mimeType = "application/vnd.noblenet-directory" - or - ext = ".nns" and mimeType = "application/vnd.noblenet-sealer" - or - ext = ".nnw" and mimeType = "application/vnd.noblenet-web" - or - ext = ".npx" and mimeType = "image/vnd.net-fpx" - or - ext = ".nsf" and mimeType = "application/vnd.lotus-notes" - or - ext = ".oa2" and mimeType = "application/vnd.fujitsu.oasys2" - or - ext = ".oa3" and mimeType = "application/vnd.fujitsu.oasys3" - or - ext = ".oas" and mimeType = "application/vnd.fujitsu.oasys" - or - ext = ".obd" and mimeType = "application/x-msbinder" - or - ext = ".oda" and mimeType = "application/oda" - or - ext = ".odc" and mimeType = "application/vnd.oasis.opendocument.chart" - or - ext = ".odf" and mimeType = "application/vnd.oasis.opendocument.formula" - or - ext = ".odg" and mimeType = "application/vnd.oasis.opendocument.graphics" - or - ext = ".odi" and mimeType = "application/vnd.oasis.opendocument.image" - or - ext = ".odp" and mimeType = "application/vnd.oasis.opendocument.presentation" - or - ext = ".ods" and mimeType = "application/vnd.oasis.opendocument.spreadsheet" - or - ext = ".odt" and mimeType = "application/vnd.oasis.opendocument.text" - or - ext = ".oga" and mimeType = "audio/ogg" - or - ext = ".ogg" and mimeType = "application/ogg" - or - ext = ".ogv" and mimeType = "video/ogg" - or - ext = ".ogx" and mimeType = "application/ogg" - or - ext = ".org" and mimeType = "application/vnd.lotus-organizer" - or - ext = ".otc" and mimeType = "application/vnd.oasis.opendocument.chart-template" - or - ext = ".otf" and mimeType = "application/vnd.oasis.opendocument.formula-template" - or - ext = ".otg" and mimeType = "application/vnd.oasis.opendocument.graphics-template" - or - ext = ".oth" and mimeType = "application/vnd.oasis.opendocument.text-web" - or - ext = ".oti" and mimeType = "application/vnd.oasis.opendocument.image-template" - or - ext = ".otm" and mimeType = "application/vnd.oasis.opendocument.text-master" - or - ext = ".ots" and mimeType = "application/vnd.oasis.opendocument.spreadsheet-template" - or - ext = ".ott" and mimeType = "application/vnd.oasis.opendocument.text-template" - or - ext = ".oxt" and mimeType = "application/vnd.openofficeorg.extension" - or - ext = ".p" and mimeType = "text/x-pascal" - or - ext = ".p10" and mimeType = "application/pkcs10" - or - ext = ".p12" and mimeType = "application/x-pkcs12" - or - ext = ".p7b" and mimeType = "application/x-pkcs7-certificates" - or - ext = ".p7m" and mimeType = "application/pkcs7-mime" - or - ext = ".p7r" and mimeType = "application/x-pkcs7-certreqresp" - or - ext = ".p7s" and mimeType = "application/pkcs7-signature" - or - ext = ".pas" and mimeType = "text/x-pascal" - or - ext = ".pbd" and mimeType = "application/vnd.powerbuilder6" - or - ext = ".pbm" and mimeType = "image/x-portable-bitmap" - or - ext = ".pcl" and mimeType = "application/vnd.hp-pcl" - or - ext = ".pclxl" and mimeType = "application/vnd.hp-pclxl" - or - ext = ".pcx" and mimeType = "image/x-pcx" - or - ext = ".pdb" and mimeType = "chemical/x-pdb" - or - ext = ".pdf" and mimeType = "application/pdf" - or - ext = ".pem" and mimeType = "application/x-x509-ca-cert" - or - ext = ".pfr" and mimeType = "application/font-tdpfr" - or - ext = ".pgm" and mimeType = "image/x-portable-graymap" - or - ext = ".pgn" and mimeType = "application/x-chess-pgn" - or - ext = ".pgp" and mimeType = "application/pgp-encrypted" - or - ext = ".pic" and mimeType = "image/x-pict" - or - ext = ".pict" and mimeType = "image/pict" - or - ext = ".pkg" and mimeType = "application/octet-stream" - or - ext = ".pki" and mimeType = "application/pkixcmp" - or - ext = ".pkipath" and mimeType = "application/pkix-pkipath" - or - ext = ".pl" and mimeType = "text/x-script.perl" - or - ext = ".plb" and mimeType = "application/vnd.3gpp.pic-bw-large" - or - ext = ".plc" and mimeType = "application/vnd.mobius.plc" - or - ext = ".plf" and mimeType = "application/vnd.pocketlearn" - or - ext = ".pls" and mimeType = "application/pls+xml" - or - ext = ".pm" and mimeType = "text/x-script.perl-module" - or - ext = ".pml" and mimeType = "application/vnd.ctc-posml" - or - ext = ".png" and mimeType = "image/png" - or - ext = ".pnm" and mimeType = "image/x-portable-anymap" - or - ext = ".pntg" and mimeType = "image/x-macpaint" - or - ext = ".portpkg" and mimeType = "application/vnd.macports.portpkg" - or - ext = ".pot" and mimeType = "application/vnd.ms-powerpoint" - or - ext = ".potm" and mimeType = "application/vnd.ms-powerpoint.template.macroEnabled.12" - or - ext = ".potx" and - mimeType = "application/vnd.openxmlformats-officedocument.presentationml.template" - or - ext = ".ppa" and mimeType = "application/vnd.ms-powerpoint" - or - ext = ".ppam" and mimeType = "application/vnd.ms-powerpoint.addin.macroEnabled.12" - or - ext = ".ppd" and mimeType = "application/vnd.cups-ppd" - or - ext = ".ppm" and mimeType = "image/x-portable-pixmap" - or - ext = ".pps" and mimeType = "application/vnd.ms-powerpoint" - or - ext = ".ppsm" and mimeType = "application/vnd.ms-powerpoint.slideshow.macroEnabled.12" - or - ext = ".ppsx" and - mimeType = "application/vnd.openxmlformats-officedocument.presentationml.slideshow" - or - ext = ".ppt" and mimeType = "application/vnd.ms-powerpoint" - or - ext = ".pptm" and mimeType = "application/vnd.ms-powerpoint.presentation.macroEnabled.12" - or - ext = ".pptx" and - mimeType = "application/vnd.openxmlformats-officedocument.presentationml.presentation" - or - ext = ".prc" and mimeType = "application/vnd.palm" - or - ext = ".pre" and mimeType = "application/vnd.lotus-freelance" - or - ext = ".prf" and mimeType = "application/pics-rules" - or - ext = ".ps" and mimeType = "application/postscript" - or - ext = ".psb" and mimeType = "application/vnd.3gpp.pic-bw-small" - or - ext = ".psd" and mimeType = "image/vnd.adobe.photoshop" - or - ext = ".ptid" and mimeType = "application/vnd.pvi.ptid1" - or - ext = ".pub" and mimeType = "application/x-mspublisher" - or - ext = ".pvb" and mimeType = "application/vnd.3gpp.pic-bw-var" - or - ext = ".pwn" and mimeType = "application/vnd.3m.post-it-notes" - or - ext = ".py" and mimeType = "text/x-script.python" - or - ext = ".pya" and mimeType = "audio/vnd.ms-playready.media.pya" - or - ext = ".pyv" and mimeType = "video/vnd.ms-playready.media.pyv" - or - ext = ".qam" and mimeType = "application/vnd.epson.quickanime" - or - ext = ".qbo" and mimeType = "application/vnd.intu.qbo" - or - ext = ".qfx" and mimeType = "application/vnd.intu.qfx" - or - ext = ".qps" and mimeType = "application/vnd.publishare-delta-tree" - or - ext = ".qt" and mimeType = "video/quicktime" - or - ext = ".qtif" and mimeType = "image/x-quicktime" - or - ext = ".qxd" and mimeType = "application/vnd.quark.quarkxpress" - or - ext = ".ra" and mimeType = "audio/x-pn-realaudio" - or - ext = ".rake" and mimeType = "text/x-script.ruby" - or - ext = ".ram" and mimeType = "audio/x-pn-realaudio" - or - ext = ".rar" and mimeType = "application/x-rar-compressed" - or - ext = ".ras" and mimeType = "image/x-cmu-raster" - or - ext = ".rb" and mimeType = "text/x-script.ruby" - or - ext = ".rcprofile" and mimeType = "application/vnd.ipunplugged.rcprofile" - or - ext = ".rdf" and mimeType = "application/rdf+xml" - or - ext = ".rdz" and mimeType = "application/vnd.data-vision.rdz" - or - ext = ".rep" and mimeType = "application/vnd.businessobjects" - or - ext = ".rgb" and mimeType = "image/x-rgb" - or - ext = ".rif" and mimeType = "application/reginfo+xml" - or - ext = ".rl" and mimeType = "application/resource-lists+xml" - or - ext = ".rlc" and mimeType = "image/vnd.fujixerox.edmics-rlc" - or - ext = ".rld" and mimeType = "application/resource-lists-diff+xml" - or - ext = ".rm" and mimeType = "application/vnd.rn-realmedia" - or - ext = ".rmp" and mimeType = "audio/x-pn-realaudio-plugin" - or - ext = ".rms" and mimeType = "application/vnd.jcp.javame.midlet-rms" - or - ext = ".rnc" and mimeType = "application/relax-ng-compact-syntax" - or - ext = ".roff" and mimeType = "text/troff" - or - ext = ".rpm" and mimeType = "application/x-redhat-package-manager" - or - ext = ".rpss" and mimeType = "application/vnd.nokia.radio-presets" - or - ext = ".rpst" and mimeType = "application/vnd.nokia.radio-preset" - or - ext = ".rq" and mimeType = "application/sparql-query" - or - ext = ".rs" and mimeType = "application/rls-services+xml" - or - ext = ".rsd" and mimeType = "application/rsd+xml" - or - ext = ".rss" and mimeType = "application/rss+xml" - or - ext = ".rtf" and mimeType = "application/rtf" - or - ext = ".rtx" and mimeType = "text/richtext" - or - ext = ".ru" and mimeType = "text/x-script.ruby" - or - ext = ".s" and mimeType = "text/x-asm" - or - ext = ".saf" and mimeType = "application/vnd.yamaha.smaf-audio" - or - ext = ".sbml" and mimeType = "application/sbml+xml" - or - ext = ".sc" and mimeType = "application/vnd.ibm.secure-container" - or - ext = ".scd" and mimeType = "application/x-msschedule" - or - ext = ".scm" and mimeType = "application/vnd.lotus-screencam" - or - ext = ".scq" and mimeType = "application/scvp-cv-request" - or - ext = ".scs" and mimeType = "application/scvp-cv-response" - or - ext = ".sdkm" and mimeType = "application/vnd.solent.sdkm+xml" - or - ext = ".sdp" and mimeType = "application/sdp" - or - ext = ".see" and mimeType = "application/vnd.seemail" - or - ext = ".sema" and mimeType = "application/vnd.sema" - or - ext = ".semd" and mimeType = "application/vnd.semd" - or - ext = ".semf" and mimeType = "application/vnd.semf" - or - ext = ".setpay" and mimeType = "application/set-payment-initiation" - or - ext = ".setreg" and mimeType = "application/set-registration-initiation" - or - ext = ".sfd" and mimeType = "application/vnd.hydrostatix.sof-data" - or - ext = ".sfs" and mimeType = "application/vnd.spotfire.sfs" - or - ext = ".sgm" and mimeType = "text/sgml" - or - ext = ".sgml" and mimeType = "text/sgml" - or - ext = ".sh" and mimeType = "application/x-sh" - or - ext = ".shar" and mimeType = "application/x-shar" - or - ext = ".shf" and mimeType = "application/shf+xml" - or - ext = ".sig" and mimeType = "application/pgp-signature" - or - ext = ".sit" and mimeType = "application/x-stuffit" - or - ext = ".sitx" and mimeType = "application/x-stuffitx" - or - ext = ".skp" and mimeType = "application/vnd.koan" - or - ext = ".slt" and mimeType = "application/vnd.epson.salt" - or - ext = ".smi" and mimeType = "application/smil+xml" - or - ext = ".snd" and mimeType = "audio/basic" - or - ext = ".so" and mimeType = "application/octet-stream" - or - ext = ".spf" and mimeType = "application/vnd.yamaha.smaf-phrase" - or - ext = ".spl" and mimeType = "application/x-futuresplash" - or - ext = ".spot" and mimeType = "text/vnd.in3d.spot" - or - ext = ".spp" and mimeType = "application/scvp-vp-response" - or - ext = ".spq" and mimeType = "application/scvp-vp-request" - or - ext = ".src" and mimeType = "application/x-wais-source" - or - ext = ".srt" and mimeType = "text/srt" - or - ext = ".srx" and mimeType = "application/sparql-results+xml" - or - ext = ".sse" and mimeType = "application/vnd.kodak-descriptor" - or - ext = ".ssf" and mimeType = "application/vnd.epson.ssf" - or - ext = ".ssml" and mimeType = "application/ssml+xml" - or - ext = ".stf" and mimeType = "application/vnd.wt.stf" - or - ext = ".stk" and mimeType = "application/hyperstudio" - or - ext = ".str" and mimeType = "application/vnd.pg.format" - or - ext = ".sus" and mimeType = "application/vnd.sus-calendar" - or - ext = ".sv4cpio" and mimeType = "application/x-sv4cpio" - or - ext = ".sv4crc" and mimeType = "application/x-sv4crc" - or - ext = ".svd" and mimeType = "application/vnd.svd" - or - ext = ".svg" and mimeType = "image/svg+xml" - or - ext = ".svgz" and mimeType = "image/svg+xml" - or - ext = ".swf" and mimeType = "application/x-shockwave-flash" - or - ext = ".swi" and mimeType = "application/vnd.arastra.swi" - or - ext = ".t" and mimeType = "text/troff" - or - ext = ".tao" and mimeType = "application/vnd.tao.intent-module-archive" - or - ext = ".tar" and mimeType = "application/x-tar" - or - ext = ".tbz" and mimeType = "application/x-bzip-compressed-tar" - or - ext = ".tcap" and mimeType = "application/vnd.3gpp2.tcap" - or - ext = ".tcl" and mimeType = "application/x-tcl" - or - ext = ".tex" and mimeType = "application/x-tex" - or - ext = ".texi" and mimeType = "application/x-texinfo" - or - ext = ".texinfo" and mimeType = "application/x-texinfo" - or - ext = ".text" and mimeType = "text/plain" - or - ext = ".tif" and mimeType = "image/tiff" - or - ext = ".tiff" and mimeType = "image/tiff" - or - ext = ".tmo" and mimeType = "application/vnd.tmobile-livetv" - or - ext = ".torrent" and mimeType = "application/x-bittorrent" - or - ext = ".tpl" and mimeType = "application/vnd.groove-tool-template" - or - ext = ".tpt" and mimeType = "application/vnd.trid.tpt" - or - ext = ".tr" and mimeType = "text/troff" - or - ext = ".tra" and mimeType = "application/vnd.trueapp" - or - ext = ".trm" and mimeType = "application/x-msterminal" - or - ext = ".ts" and mimeType = "video/mp2t" - or - ext = ".tsv" and mimeType = "text/tab-separated-values" - or - ext = ".ttf" and mimeType = "application/octet-stream" - or - ext = ".twd" and mimeType = "application/vnd.simtech-mindmapper" - or - ext = ".txd" and mimeType = "application/vnd.genomatix.tuxedo" - or - ext = ".txf" and mimeType = "application/vnd.mobius.txf" - or - ext = ".txt" and mimeType = "text/plain" - or - ext = ".ufd" and mimeType = "application/vnd.ufdl" - or - ext = ".umj" and mimeType = "application/vnd.umajin" - or - ext = ".unityweb" and mimeType = "application/vnd.unity" - or - ext = ".uoml" and mimeType = "application/vnd.uoml+xml" - or - ext = ".uri" and mimeType = "text/uri-list" - or - ext = ".ustar" and mimeType = "application/x-ustar" - or - ext = ".utz" and mimeType = "application/vnd.uiq.theme" - or - ext = ".uu" and mimeType = "text/x-uuencode" - or - ext = ".vcd" and mimeType = "application/x-cdlink" - or - ext = ".vcf" and mimeType = "text/x-vcard" - or - ext = ".vcg" and mimeType = "application/vnd.groove-vcard" - or - ext = ".vcs" and mimeType = "text/x-vcalendar" - or - ext = ".vcx" and mimeType = "application/vnd.vcx" - or - ext = ".vis" and mimeType = "application/vnd.visionary" - or - ext = ".viv" and mimeType = "video/vnd.vivo" - or - ext = ".vrml" and mimeType = "model/vrml" - or - ext = ".vsd" and mimeType = "application/vnd.visio" - or - ext = ".vsf" and mimeType = "application/vnd.vsf" - or - ext = ".vtt" and mimeType = "text/vtt" - or - ext = ".vtu" and mimeType = "model/vnd.vtu" - or - ext = ".vxml" and mimeType = "application/voicexml+xml" - or - ext = ".war" and mimeType = "application/java-archive" - or - ext = ".wasm" and mimeType = "application/wasm" - or - ext = ".wav" and mimeType = "audio/x-wav" - or - ext = ".wax" and mimeType = "audio/x-ms-wax" - or - ext = ".wbmp" and mimeType = "image/vnd.wap.wbmp" - or - ext = ".wbs" and mimeType = "application/vnd.criticaltools.wbs+xml" - or - ext = ".wbxml" and mimeType = "application/vnd.wap.wbxml" - or - ext = ".webm" and mimeType = "video/webm" - or - ext = ".webp" and mimeType = "image/webp" - or - ext = ".wm" and mimeType = "video/x-ms-wm" - or - ext = ".wma" and mimeType = "audio/x-ms-wma" - or - ext = ".wmd" and mimeType = "application/x-ms-wmd" - or - ext = ".wmf" and mimeType = "application/x-msmetafile" - or - ext = ".wml" and mimeType = "text/vnd.wap.wml" - or - ext = ".wmlc" and mimeType = "application/vnd.wap.wmlc" - or - ext = ".wmls" and mimeType = "text/vnd.wap.wmlscript" - or - ext = ".wmlsc" and mimeType = "application/vnd.wap.wmlscriptc" - or - ext = ".wmv" and mimeType = "video/x-ms-wmv" - or - ext = ".wmx" and mimeType = "video/x-ms-wmx" - or - ext = ".wmz" and mimeType = "application/x-ms-wmz" - or - ext = ".woff" and mimeType = "application/font-woff" - or - ext = ".woff2" and mimeType = "application/font-woff2" - or - ext = ".wpd" and mimeType = "application/vnd.wordperfect" - or - ext = ".wpl" and mimeType = "application/vnd.ms-wpl" - or - ext = ".wps" and mimeType = "application/vnd.ms-works" - or - ext = ".wqd" and mimeType = "application/vnd.wqd" - or - ext = ".wri" and mimeType = "application/x-mswrite" - or - ext = ".wrl" and mimeType = "model/vrml" - or - ext = ".wsdl" and mimeType = "application/wsdl+xml" - or - ext = ".wspolicy" and mimeType = "application/wspolicy+xml" - or - ext = ".wtb" and mimeType = "application/vnd.webturbo" - or - ext = ".wvx" and mimeType = "video/x-ms-wvx" - or - ext = ".x3d" and mimeType = "application/vnd.hzn-3d-crossword" - or - ext = ".xar" and mimeType = "application/vnd.xara" - or - ext = ".xbd" and mimeType = "application/vnd.fujixerox.docuworks.binder" - or - ext = ".xbm" and mimeType = "image/x-xbitmap" - or - ext = ".xdm" and mimeType = "application/vnd.syncml.dm+xml" - or - ext = ".xdp" and mimeType = "application/vnd.adobe.xdp+xml" - or - ext = ".xdw" and mimeType = "application/vnd.fujixerox.docuworks" - or - ext = ".xenc" and mimeType = "application/xenc+xml" - or - ext = ".xer" and mimeType = "application/patch-ops-error+xml" - or - ext = ".xfdf" and mimeType = "application/vnd.adobe.xfdf" - or - ext = ".xfdl" and mimeType = "application/vnd.xfdl" - or - ext = ".xhtml" and mimeType = "application/xhtml+xml" - or - ext = ".xif" and mimeType = "image/vnd.xiff" - or - ext = ".xla" and mimeType = "application/vnd.ms-excel" - or - ext = ".xlam" and mimeType = "application/vnd.ms-excel.addin.macroEnabled.12" - or - ext = ".xls" and mimeType = "application/vnd.ms-excel" - or - ext = ".xlsb" and mimeType = "application/vnd.ms-excel.sheet.binary.macroEnabled.12" - or - ext = ".xlsx" and mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" - or - ext = ".xlsm" and mimeType = "application/vnd.ms-excel.sheet.macroEnabled.12" - or - ext = ".xlt" and mimeType = "application/vnd.ms-excel" - or - ext = ".xltx" and - mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.template" - or - ext = ".xml" and mimeType = "application/xml" - or - ext = ".xo" and mimeType = "application/vnd.olpc-sugar" - or - ext = ".xop" and mimeType = "application/xop+xml" - or - ext = ".xpm" and mimeType = "image/x-xpixmap" - or - ext = ".xpr" and mimeType = "application/vnd.is-xpr" - or - ext = ".xps" and mimeType = "application/vnd.ms-xpsdocument" - or - ext = ".xpw" and mimeType = "application/vnd.intercon.formnet" - or - ext = ".xsl" and mimeType = "application/xml" - or - ext = ".xslt" and mimeType = "application/xslt+xml" - or - ext = ".xsm" and mimeType = "application/vnd.syncml+xml" - or - ext = ".xspf" and mimeType = "application/xspf+xml" - or - ext = ".xul" and mimeType = "application/vnd.mozilla.xul+xml" - or - ext = ".xwd" and mimeType = "image/x-xwindowdump" - or - ext = ".xyz" and mimeType = "chemical/x-xyz" - or - ext = ".yaml" and mimeType = "text/yaml" - or - ext = ".yml" and mimeType = "text/yaml" - or - ext = ".zaz" and mimeType = "application/vnd.zzazz.deck+xml" - or - ext = ".zip" and mimeType = "application/zip" - or - ext = ".zmm" and mimeType = "application/vnd.handheld-entertainment+xml" -} - -/** - * Provides modeling for the `Mime` component of the `Rack` library. - */ -module Mime { - /** A call to `Rack::Mime.mime_type`. This method maps file extensions to MIME types. */ - class MimetypeCall extends DataFlow::CallNode { - MimetypeCall() { - this = API::getTopLevelMember("Rack").getMember("Mime").getAMethodCall("mime_type") - } - - private string getExtension() { - result = this.getArgument(0).getConstantValue().getStringlikeValue() - } - - /** Gets the canonical MIME type string returned by this call. */ - string getMimetype() { mimetypeMatches(this.getExtension(), result) } - } -} diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.expected b/ruby/ql/test/library-tests/frameworks/rack/Rack.expected index a2671c95cb7..c55afeb7801 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.expected +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.expected @@ -6,8 +6,6 @@ rackApps | rack.rb:59:1:75:3 | Baz | rack.rb:60:12:60:14 | env | rackResponseContentTypes | rack.rb:8:5:8:38 | call to [] | rack.rb:7:34:7:45 | "text/plain" | -| rack.rb:20:5:20:27 | call to [] | rack.rb:19:28:19:54 | call to mime_type | -mimetypeCalls -| rack.rb:19:28:19:54 | call to mime_type | application/x-gzip | +| rack.rb:20:5:20:27 | call to [] | rack.rb:19:28:19:38 | "text/html" | redirectResponses | rack.rb:43:5:43:45 | call to [] | rack.rb:42:30:42:40 | "/foo.html" | diff --git a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql index e1f1c506994..9b5d0629a9f 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/Rack.ql +++ b/ruby/ql/test/library-tests/frameworks/rack/Rack.ql @@ -12,10 +12,6 @@ query predicate rackResponseContentTypes( contentType = resp.getMimetypeOrContentTypeArg() } -query predicate mimetypeCalls(Rack::Mime::MimetypeCall c, string mimetype) { - mimetype = c.getMimetype() -} - query predicate redirectResponses(Rack::Response::RedirectResponse resp, DataFlow::Node location) { location = resp.getRedirectLocation() } diff --git a/ruby/ql/test/library-tests/frameworks/rack/rack.rb b/ruby/ql/test/library-tests/frameworks/rack/rack.rb index c2e2598e5ec..9f743496ad2 100644 --- a/ruby/ql/test/library-tests/frameworks/rack/rack.rb +++ b/ruby/ql/test/library-tests/frameworks/rack/rack.rb @@ -16,7 +16,7 @@ class Proxy def call(the_env) status, headers, body = @app.call(the_env) - headers.content_type = Rack::Mime.mime_type(".gz") + headers.content_type = "text/html" [status, headers, body] end end From 8ef8a0d2f63bd9b4e66fa95a1500b5272bf0e4d6 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 20 Jun 2023 14:59:13 +0100 Subject: [PATCH 233/364] qlformat --- ruby/ql/lib/codeql/ruby/frameworks/Rack.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll index 4d9342d8805..6963f37a81c 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Rack.qll @@ -7,8 +7,8 @@ */ module Rack { import rack.internal.App -import rack.internal.Response::Public as Response + import rack.internal.Response::Public as Response -/** DEPRECATED: Alias for App::AppCandidate */ -deprecated class AppCandidate = App::AppCandidate; + /** DEPRECATED: Alias for App::AppCandidate */ + deprecated class AppCandidate = App::AppCandidate; } From cb2de69f5a052877f14e70e533fbdba6a91fa49d Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 20 Jun 2023 16:13:38 +0200 Subject: [PATCH 234/364] python: consolidate tests also change `Foo` -> `foo` --- .../model-summaries/InlineTaintTest.expected | 3 + .../model-summaries/InlineTaintTest.ql | 3 + .../NormalDataflowTest.expected | 0 .../{dataflow => }/NormalDataflowTest.ql | 0 .../model-summaries/TestSummaries.qll | 25 ++++ .../dataflow/TestSummaries.qll | 20 --- .../dataflow/model_summaries.py | 69 ---------- .../model-summaries/model_summaries.py | 128 ++++++++++++++++++ .../taint/NormalTaintTrackingTest.expected | 2 - .../taint/NormalTaintTrackingTest.ql | 3 - .../model-summaries/taint/TestSummaries.qll | 19 --- .../taint/model_summaries_taint.py | 70 ---------- 12 files changed, 159 insertions(+), 183 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.expected create mode 100644 python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ql rename python/ql/test/experimental/dataflow/model-summaries/{dataflow => }/NormalDataflowTest.expected (100%) rename python/ql/test/experimental/dataflow/model-summaries/{dataflow => }/NormalDataflowTest.ql (100%) create mode 100644 python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll delete mode 100644 python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll delete mode 100644 python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py create mode 100644 python/ql/test/experimental/dataflow/model-summaries/model_summaries.py delete mode 100644 python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected delete mode 100644 python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.ql delete mode 100644 python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll delete mode 100644 python/ql/test/experimental/dataflow/model-summaries/taint/model_summaries_taint.py diff --git a/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.expected b/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.expected new file mode 100644 index 00000000000..79d760d87f4 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.expected @@ -0,0 +1,3 @@ +argumentToEnsureNotTaintedNotMarkedAsSpurious +untaintedArgumentToEnsureTaintedNotMarkedAsMissing +failures diff --git a/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ql b/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ql new file mode 100644 index 00000000000..f7f84cb8479 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ql @@ -0,0 +1,3 @@ +import python +private import TestSummaries +import experimental.meta.InlineTaintTest diff --git a/python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.expected similarity index 100% rename from python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.expected rename to python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.expected diff --git a/python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.ql b/python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ql similarity index 100% rename from python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.ql rename to python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ql diff --git a/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll b/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll new file mode 100644 index 00000000000..5f1e0a1f90b --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll @@ -0,0 +1,25 @@ +private import python +private import semmle.python.dataflow.new.FlowSummary +private import semmle.python.frameworks.data.ModelsAsData +private import semmle.python.ApiGraphs + +private class StepsFromModel extends ModelInput::SummaryModelCsv { + override predicate row(string row) { + row = + [ + "foo;Member[MS_identity];Argument[0];ReturnValue;value", + "foo;Member[MS_apply_lambda];Argument[1];Argument[0].Parameter[0];value", + "foo;Member[MS_apply_lambda];Argument[0].ReturnValue;ReturnValue;value", + "foo;Member[MS_reversed];Argument[0].ListElement;ReturnValue.ListElement;value", + "foo;Member[MS_reversed];Argument[0];ReturnValue;taint", + "foo;Member[MS_list_map];Argument[1].ListElement;Argument[0].Parameter[0];value", + "foo;Member[MS_list_map];Argument[0].ReturnValue;ReturnValue.ListElement;value", + "foo;Member[MS_list_map];Argument[1];ReturnValue;taint", + "foo;Member[MS_append_to_list];Argument[0].ListElement;ReturnValue.ListElement;value", + "foo;Member[MS_append_to_list];Argument[1];ReturnValue.ListElement;value", + "foo;Member[MS_append_to_list];Argument[0];ReturnValue;taint", + "foo;Member[MS_append_to_list];Argument[1];ReturnValue;taint", + "json;Member[MS_loads];Argument[0];ReturnValue;taint" + ] + } +} diff --git a/python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll b/python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll deleted file mode 100644 index d97702eec41..00000000000 --- a/python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll +++ /dev/null @@ -1,20 +0,0 @@ -private import python -private import semmle.python.dataflow.new.FlowSummary -private import semmle.python.frameworks.data.ModelsAsData -private import semmle.python.ApiGraphs - -private class StepsFromModel extends ModelInput::SummaryModelCsv { - override predicate row(string row) { - row = - [ - "Foo;Member[MS_identity];Argument[0];ReturnValue;value", - "Foo;Member[MS_apply_lambda];Argument[1];Argument[0].Parameter[0];value", - "Foo;Member[MS_apply_lambda];Argument[0].ReturnValue;ReturnValue;value", - "Foo;Member[MS_reversed];Argument[0].ListElement;ReturnValue.ListElement;value", - "Foo;Member[MS_list_map];Argument[1].ListElement;Argument[0].Parameter[0];value", - "Foo;Member[MS_list_map];Argument[0].ReturnValue;ReturnValue.ListElement;value", - "Foo;Member[MS_append_to_list];Argument[0].ListElement;ReturnValue.ListElement;value", - "Foo;Member[MS_append_to_list];Argument[1];ReturnValue.ListElement;value" - ] - } -} diff --git a/python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py deleted file mode 100644 index c81fddf44ec..00000000000 --- a/python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py +++ /dev/null @@ -1,69 +0,0 @@ - -import sys -import os - -sys.path.append(os.path.dirname(os.path.dirname((__file__)))) -from testlib import expects - -# These are defined so that we can evaluate the test code. -NONSOURCE = "not a source" -SOURCE = "source" - - -def is_source(x): - return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j - - -def SINK(x): - if is_source(x): - print("OK") - else: - print("Unexpected flow", x) - - -def SINK_F(x): - if is_source(x): - print("Unexpected flow", x) - else: - print("OK") - - -from Foo import MS_identity, MS_apply_lambda, MS_reversed, MS_list_map, MS_append_to_list - -# Simple summary -tainted = MS_identity(SOURCE) -SINK(tainted) # $ flow="SOURCE, l:-1 -> tainted" - -# Lambda summary -tainted_lambda = MS_apply_lambda(lambda x: [x], SOURCE) -SINK(tainted_lambda[0]) # $ flow="SOURCE, l:-1 -> tainted_lambda[0]" - -# A lambda that breaks the flow -untainted_lambda = MS_apply_lambda(lambda x: 1, SOURCE) -SINK_F(untainted_lambda) - -# Collection summaries -tainted_list = MS_reversed([SOURCE]) -SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" - -# Complex summaries -def box(x): - return [x] - -tainted_mapped = MS_list_map(box, [SOURCE]) -SINK(tainted_mapped[0][0]) # $ flow="SOURCE, l:-1 -> tainted_mapped[0][0]" - -def explicit_identity(x): - return x - -tainted_mapped_explicit = MS_list_map(explicit_identity, [SOURCE]) -SINK(tainted_mapped_explicit[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" - -tainted_mapped_summary = MS_list_map(MS_identity, [SOURCE]) -SINK(tainted_mapped_summary[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" - -tainted_list = MS_append_to_list([], SOURCE) -SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" - -tainted_list = MS_append_to_list([SOURCE], NONSOURCE) -SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" diff --git a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py new file mode 100644 index 00000000000..3a98e04ceb7 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py @@ -0,0 +1,128 @@ + +import sys +import os + +sys.path.append(os.path.dirname(os.path.dirname((__file__)))) +from testlib import expects + +# These are defined so that we can evaluate the test code. +NONSOURCE = "not a source" +SOURCE = "source" + + +def is_source(x): + return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j + + +def SINK(x): + if is_source(x): + print("OK") + else: + print("Unexpected flow", x) + + +def SINK_F(x): + if is_source(x): + print("Unexpected flow", x) + else: + print("OK") + +ensure_tainted = ensure_not_tainted = print +TAINTED_STRING = "TAINTED_STRING" + +from foo import MS_identity, MS_apply_lambda, MS_reversed, MS_list_map, MS_append_to_list + +# Simple summary +via_identity = MS_identity(SOURCE) +SINK(via_identity) # $ flow="SOURCE, l:-1 -> via_identity" + +tainted = MS_identity(TAINTED_STRING) +ensure_tainted(tainted) # $ tainted + + +# Lambda summary +via_lambda = MS_apply_lambda(lambda x: [x], SOURCE) +SINK(via_lambda[0]) # $ flow="SOURCE, l:-1 -> via_lambda[0]" + +tainted_lambda = MS_apply_lambda(lambda x: [x], TAINTED_STRING) +ensure_tainted(tainted_lambda) # $ tainted + + +# A lambda that breaks the flow +not_via_lambda = MS_apply_lambda(lambda x: 1, SOURCE) +SINK_F(not_via_lambda) + +untainted_lambda = MS_apply_lambda(lambda x: 1, TAINTED_STRING) +ensure_not_tainted(untainted_lambda) + +# Collection summaries +via_reversed = MS_reversed([SOURCE]) +SINK(via_reversed[0]) # $ flow="SOURCE, l:-1 -> via_reversed[0]" + +tainted_list = MS_reversed([TAINTED_STRING]) +ensure_tainted(tainted_list[0]) # $ tainted + +# Complex summaries +def box(x): + return [x] + +via_map = MS_list_map(box, [SOURCE]) +SINK(via_map[0][0]) # $ flow="SOURCE, l:-1 -> via_map[0][0]" + +tainted_mapped = MS_list_map(box, [TAINTED_STRING]) +ensure_tainted(tainted_mapped[0][0]) # $ tainted + +def explicit_identity(x): + return x + +via_map_explicit = MS_list_map(explicit_identity, [SOURCE]) +SINK(via_map_explicit[0]) # $ flow="SOURCE, l:-1 -> via_map_explicit[0]" + +tainted_mapped_explicit = MS_list_map(explicit_identity, [TAINTED_STRING]) +tainted_mapped_explicit_implicit = MS_list_map(explicit_identity, TAINTED_LIST) +ensure_tainted( + tainted_mapped_explicit, # $ tainted + tainted_mapped_explicit[0], # $ tainted + tainted_mapped_explicit_implicit, # $ tainted + tainted_mapped_explicit_implicit[0] # $ tainted + ) + +via_map_summary = MS_list_map(MS_identity, [SOURCE]) +SINK(via_map_summary[0]) # $ flow="SOURCE, l:-1 -> via_map_summary[0]" + +tainted_mapped_summary = MS_list_map(MS_identity, [TAINTED_STRING]) +tainted_mapped_summary_implicit = MS_list_map(MS_identity, TAINTED_LIST) +ensure_tainted( + tainted_mapped_summary, # $ tainted + tainted_mapped_summary[0], # $ tainted + tainted_mapped_summary_implicit, # $ tainted + tainted_mapped_summary_implicit[0] # $ tainted + ) + +via_append_el = MS_append_to_list([], SOURCE) +SINK(via_append_el[0]) # $ flow="SOURCE, l:-1 -> via_append_el[0]" + +tainted_list_el = MS_append_to_list([], TAINTED_STRING) +ensure_tainted( + tainted_list_el, # $ tainted + tainted_list_el[0] # $ tainted + ) + +via_append = MS_append_to_list([SOURCE], NONSOURCE) +SINK(via_append[0]) # $ flow="SOURCE, l:-1 -> via_append[0]" + +tainted_list = MS_append_to_list([TAINTED_STRING], NONSOURCE) +tainted_list_implicit = MS_append_to_list(TAINTED_LIST, NONSOURCE) +ensure_tainted( + tainted_list, # $ tainted + tainted_list[0], # $ tainted + tainted_list_implicit, # $ tainted + tainted_list_implicit[0] # $ tainted + ) + +from json import MS_loads as json_loads +tainted_resultlist = json_loads(TAINTED_STRING) +ensure_tainted( + tainted_resultlist, # $ tainted + tainted_resultlist[0] # $ tainted + ) diff --git a/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected b/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected deleted file mode 100644 index 3875da4e143..00000000000 --- a/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected +++ /dev/null @@ -1,2 +0,0 @@ -missingAnnotationOnSink -failures diff --git a/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.ql b/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.ql deleted file mode 100644 index afb44b6b2ed..00000000000 --- a/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.ql +++ /dev/null @@ -1,3 +0,0 @@ -import python -private import TestSummaries -import experimental.dataflow.TestUtil.NormalTaintTrackingTest diff --git a/python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll b/python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll deleted file mode 100644 index 57861d3c022..00000000000 --- a/python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll +++ /dev/null @@ -1,19 +0,0 @@ -private import python -private import semmle.python.dataflow.new.FlowSummary -private import semmle.python.frameworks.data.ModelsAsData -private import semmle.python.ApiGraphs - -private class StepsFromModel extends ModelInput::SummaryModelCsv { - override predicate row(string row) { - row = - [ - "Foo;Member[MS_identity];Argument[0];ReturnValue;value", - "Foo;Member[MS_apply_lambda];Argument[1];Argument[0].Parameter[0];value", - "Foo;Member[MS_apply_lambda];Argument[0].ReturnValue;ReturnValue;value", - "Foo;Member[MS_reversed];Argument[0];ReturnValue;taint", - "Foo;Member[MS_list_map];Argument[1];ReturnValue;taint", - "Foo;Member[MS_append_to_list];Argument[0];ReturnValue;taint", - "json;Member[MS_loads];Argument[0];ReturnValue;taint" - ] - } -} diff --git a/python/ql/test/experimental/dataflow/model-summaries/taint/model_summaries_taint.py b/python/ql/test/experimental/dataflow/model-summaries/taint/model_summaries_taint.py deleted file mode 100644 index 44ca79c116e..00000000000 --- a/python/ql/test/experimental/dataflow/model-summaries/taint/model_summaries_taint.py +++ /dev/null @@ -1,70 +0,0 @@ - -import sys -import os - -sys.path.append(os.path.dirname(os.path.dirname((__file__)))) -from testlib import expects - -# These are defined so that we can evaluate the test code. -NONSOURCE = "not a source" -SOURCE = "source" - - -def is_source(x): - return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j - - -def SINK(x): - if is_source(x): - print("OK") - else: - print("Unexpected flow", x) - - -def SINK_F(x): - if is_source(x): - print("Unexpected flow", x) - else: - print("OK") - - -from Foo import MS_identity, MS_apply_lambda, MS_reversed, MS_list_map, MS_append_to_list - -# Simple summary -tainted = MS_identity(SOURCE) -SINK(tainted) # $ flow="SOURCE, l:-1 -> tainted" - -# Lambda summary -tainted_lambda = MS_apply_lambda(lambda x: x + 1, SOURCE) -SINK(tainted_lambda) # $ flow="SOURCE, l:-1 -> tainted_lambda" - -# A lambda that breaks the flow -untainted_lambda = MS_apply_lambda(lambda x: 1, SOURCE) -SINK_F(untainted_lambda) - -# Collection summaries -tainted_list = MS_reversed([SOURCE]) -SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" - -# Complex summaries -def add_colon(x): - return x + ":" - -tainted_mapped = MS_list_map(add_colon, [SOURCE]) -SINK(tainted_mapped[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped[0]" - -def explicit_identity(x): - return x - -tainted_mapped_explicit = MS_list_map(explicit_identity, [SOURCE]) -SINK(tainted_mapped_explicit[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" - -tainted_mapped_summary = MS_list_map(MS_identity, [SOURCE]) -SINK(tainted_mapped_summary[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" - -tainted_list = MS_append_to_list([SOURCE], NONSOURCE) -SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" - -from json import MS_loads as json_loads -tainted_resultlist = json_loads(SOURCE) -SINK(tainted_resultlist[0]) # $ flow="SOURCE, l:-1 -> tainted_resultlist[0]" From c501fa52890f514a542a0093065aaa0345947d09 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 20 Jun 2023 15:27:51 +0100 Subject: [PATCH 235/364] Swift: Add more test cases exploring the timeout. --- swift/ql/test/library-tests/regex/redos_variants.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index d1ddc1a198c..4c2b16626a7 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -380,7 +380,12 @@ func myRegexpVariantsTests(myUrl: URL) throws { // BAD // TODO: QL evaluation times out (for test, at 5 minutes) + // times out: // _ = try Regex(#"(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-"#).firstMatch(in: tainted) // $ redos-vulnerable= + // a simpler regex that times out: +// _ = try Regex(#"(\w*foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar)+"#).firstMatch(in: tainted) // $ redos-vulnerable= + // a simpler regerx that doesn't time out but is slow to evaluate: +// _ = try Regex(#"(\w*foobarfoobarfoobar)+"#).firstMatch(in: tainted) // $ redos-vulnerable= // BAD (but cannot currently construct a prefix) // attack string: "aa" + "b" x lots + "!" From 36cb60c746ec7aac4f5d9bd173658710bee04044 Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Tue, 20 Jun 2023 17:22:56 +0000 Subject: [PATCH 236/364] Add fixed proposition for NodeJS --- .../CWE-798/HardcodedCredentials.qhelp | 4 ++++ .../HardcodedCredentialsHttpRequest.js | 4 ++-- .../HardcodedCredentialsHttpRequestFixed.js | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequestFixed.js diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp index 9f6fb3ddfa0..ee5adb1cb00 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp @@ -33,6 +33,10 @@ username and password, which can be set externally without hard-coding credentials in the source code.

    + + For example, in a NodeJS environment : + +
    diff --git a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js index 5890475085d..2732e2e1851 100644 --- a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js +++ b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js @@ -11,8 +11,8 @@ headers.append('Authorization', 'Basic' + base64.encode(username + ":" + passwor fetch(url, {method:'GET', headers: headers, - //credentials: 'user:passwd' + credentials: `${user}:${passwd}` }) .then(response => response.json()) .then(json => console.log(json)); -//.done(); +.done(); diff --git a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequestFixed.js b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequestFixed.js new file mode 100644 index 00000000000..5886e14d580 --- /dev/null +++ b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequestFixed.js @@ -0,0 +1,18 @@ +let base64 = require('base-64'); + +let url = 'http://example.org/auth'; +let username = process.env.USERNAME; +let password = process.env.PASSWORD; + +let headers = new Headers(); + +//headers.append('Content-Type', 'text/json'); +headers.append('Authorization', 'Basic' + base64.encode(username + ":" + password)); + +fetch(url, {method:'GET', + headers: headers, + credentials: `${user}:${passwd}` + }) +.then(response => response.json()) +.then(json => console.log(json)); +.done(); From 2a2f6de78c2b8cf2faefb02e3f4361fc6654f10f Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Tue, 20 Jun 2023 17:27:37 +0000 Subject: [PATCH 237/364] fixed text not in a tag --- .../ql/src/Security/CWE-798/HardcodedCredentials.qhelp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp index ee5adb1cb00..60c37eed8c0 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp @@ -34,7 +34,10 @@ credentials in the source code.

    - For example, in a NodeJS environment : +

    + For example, in a NodeJS environment : +

    +
    From 59147ad6742172235f2a66ac5cc7ae20e0c1dc17 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 20 Jun 2023 15:27:39 +0200 Subject: [PATCH 238/364] QL: Add more tests for `MissingOverride.ql` --- .../MissingOverride/MissingOverride.expected | 3 +++ .../queries/style/MissingOverride/Test.qll | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/ql/ql/test/queries/style/MissingOverride/MissingOverride.expected b/ql/ql/test/queries/style/MissingOverride/MissingOverride.expected index 2ef0dd4b1ad..915a92c85f5 100644 --- a/ql/ql/test/queries/style/MissingOverride/MissingOverride.expected +++ b/ql/ql/test/queries/style/MissingOverride/MissingOverride.expected @@ -1 +1,4 @@ | Test.qll:12:13:12:16 | ClassPredicate test | Wrong.test overrides $@ but does not have an override annotation. | Test.qll:4:13:4:16 | ClassPredicate test | Super.test | +| Test.qll:18:13:18:16 | ClassPredicate test | Wrong2.test overrides $@ but does not have an override annotation. | Test.qll:4:13:4:16 | ClassPredicate test | Super.test | +| Test.qll:24:13:24:16 | ClassPredicate test | Correct2.test overrides $@ but does not have an override annotation. | Test.qll:4:13:4:16 | ClassPredicate test | Super.test | +| Test.qll:36:13:36:16 | ClassPredicate test | Correct4.test overrides $@ but does not have an override annotation. | Test.qll:32:13:32:16 | ClassPredicate test | Super2.test | diff --git a/ql/ql/test/queries/style/MissingOverride/Test.qll b/ql/ql/test/queries/style/MissingOverride/Test.qll index e7f6a2c6b87..82d5199bf9e 100644 --- a/ql/ql/test/queries/style/MissingOverride/Test.qll +++ b/ql/ql/test/queries/style/MissingOverride/Test.qll @@ -11,3 +11,27 @@ class Correct extends Super { class Wrong extends Super { predicate test(int i) { i = 2 } } + +class Mid extends Super { } + +class Wrong2 extends Mid { + predicate test(int i) { i = 2 } +} + +final class SuperFinal = Super; + +class Correct2 extends SuperFinal { + predicate test(int i) { i = 4 } +} + +class Correct3 extends AstNode instanceof SuperFinal { + predicate test(int i) { i = 4 } +} + +final class Super2 extends AstNode { + predicate test(int i) { i = [1 .. 5] } +} + +class Correct4 extends Super2 { + predicate test(int i) { i = 3 } +} From d1184f0b3cb8d4ff262c71410b9ff396a008680f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 20 Jun 2023 16:18:02 +0200 Subject: [PATCH 239/364] C#: Base the AlertSupression test on stubs. --- csharp/ql/test/query-tests/AlertSuppression/options | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 csharp/ql/test/query-tests/AlertSuppression/options diff --git a/csharp/ql/test/query-tests/AlertSuppression/options b/csharp/ql/test/query-tests/AlertSuppression/options new file mode 100644 index 00000000000..77b22963f5c --- /dev/null +++ b/csharp/ql/test/query-tests/AlertSuppression/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj From ada49dbb2ce4a843f300d5245c6bd1832ccadff1 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 21 Jun 2023 08:46:33 +0200 Subject: [PATCH 240/364] C#: Specific language version not needed in options file for API Abuse/NoDisposeCallOnLocalIDisposable. --- .../API Abuse/NoDisposeCallOnLocalIDisposable/options | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options index 08e01d88cc1..b8a701342a7 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options @@ -1 +1 @@ -semmle-extractor-options: --cil /langversion:8.0 /r:System.Xml.dll /r:System.Xml.ReaderWriter.dll /r:System.Private.Xml.dll /r:System.ComponentModel.Primitives.dll /r:System.IO.Compression.dll /r:System.Runtime.Extensions.dll +semmle-extractor-options: --cil /r:System.Xml.dll /r:System.Xml.ReaderWriter.dll /r:System.Private.Xml.dll /r:System.ComponentModel.Primitives.dll /r:System.IO.Compression.dll /r:System.Runtime.Extensions.dll From 4546d8f0bff97d28bdd6666aaacb9b1e38404f8f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 21 Jun 2023 09:10:08 +0200 Subject: [PATCH 241/364] C#: Base API Abuse/UncheckedReturnValue test case on stubs, clean up test and update expected output. --- .../UncheckedReturnValue.cs | 28 ++----------------- .../UncheckedReturnValue.expected | 12 ++++---- .../API Abuse/UncheckedReturnValue/options | 2 ++ 3 files changed, 10 insertions(+), 32 deletions(-) create mode 100644 csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/options diff --git a/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/UncheckedReturnValue.cs b/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/UncheckedReturnValue.cs index f4a4944f4fb..cf290a84bcb 100644 --- a/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/UncheckedReturnValue.cs +++ b/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/UncheckedReturnValue.cs @@ -1,11 +1,6 @@ using System; -class HashSet -{ - public bool Add(T t) - { - return true; - } -} +using System.Text; +using System.Collections.Generic; class C1 { @@ -30,11 +25,6 @@ class C1 } } -class StringBuilder -{ - public StringBuilder Append(string s) { return this; } -} - class C2 { static void Main(string[] args) @@ -59,20 +49,6 @@ class C2 } } -namespace System.IO -{ - public abstract class Stream - { - public abstract int Read(byte[] buffer, int offset, int count); - public virtual int ReadByte() { return 0; } - } - - public class MemoryStream : Stream - { - public override int Read(byte[] buffer, int offset, int count) { return 0; } - } -} - class C3 { static void Main(string[] args) diff --git a/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/UncheckedReturnValue.expected b/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/UncheckedReturnValue.expected index 371205cbc6b..e463ee956eb 100644 --- a/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/UncheckedReturnValue.expected +++ b/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/UncheckedReturnValue.expected @@ -1,8 +1,8 @@ -| UncheckedReturnValue.cs:29:9:29:31 | call to method Add | Result of call to 'Add' is ignored, but 90% of calls to this method have their result used. | -| UncheckedReturnValue.cs:91:9:91:26 | call to method Read | Result of call to 'Read' is ignored, but should always be checked. | -| UncheckedReturnValue.cs:92:9:92:20 | call to method ReadByte | Result of call to 'ReadByte' is ignored, but should always be checked. | -| UncheckedReturnValue.cs:109:9:109:17 | call to method M1 | Result of call to 'M1' is ignored, but 90% of calls to this method have their result used. | -| UncheckedReturnValue.cs:130:9:130:21 | call to method M2 | Result of call to 'M2' is ignored, but 90% of calls to this method have their result used. | -| UncheckedReturnValue.cs:142:9:142:20 | call to method M3 | Result of call to 'M3' is ignored, but 90% of calls to this method have their result used. | +| UncheckedReturnValue.cs:24:9:24:31 | call to method Add | Result of call to 'Add' is ignored, but 90% of calls to this method have their result used. | +| UncheckedReturnValue.cs:67:9:67:26 | call to method Read | Result of call to 'Read' is ignored, but should always be checked. | +| UncheckedReturnValue.cs:68:9:68:20 | call to method ReadByte | Result of call to 'ReadByte' is ignored, but should always be checked. | +| UncheckedReturnValue.cs:85:9:85:17 | call to method M1 | Result of call to 'M1' is ignored, but 90% of calls to this method have their result used. | +| UncheckedReturnValue.cs:106:9:106:21 | call to method M2 | Result of call to 'M2' is ignored, but 90% of calls to this method have their result used. | +| UncheckedReturnValue.cs:118:9:118:20 | call to method M3 | Result of call to 'M3' is ignored, but 90% of calls to this method have their result used. | | UncheckedReturnValueBad.cs:29:9:29:20 | call to method DoPrint | Result of call to 'DoPrint' is ignored, but 90% of calls to this method have their result used. | | UncheckedReturnValueBad.cs:36:13:36:40 | call to method Read | Result of call to 'Read' is ignored, but should always be checked. | diff --git a/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/options b/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/UncheckedReturnValue/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj From 0e263fb7444fb58de147ed724692ea7c870d7dff Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 21 Jun 2023 09:28:27 +0200 Subject: [PATCH 242/364] C#: Base API Abuse/DisposeNotCalledOnException test case on stubs. Since the stubs requires C# 11 the language version has been removed from the options (also it doesn't affect the output). --- .../query-tests/API Abuse/DisposeNotCalledOnException/options | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/query-tests/API Abuse/DisposeNotCalledOnException/options b/csharp/ql/test/query-tests/API Abuse/DisposeNotCalledOnException/options index a0b23f3ee8b..7faed1b92ed 100644 --- a/csharp/ql/test/query-tests/API Abuse/DisposeNotCalledOnException/options +++ b/csharp/ql/test/query-tests/API Abuse/DisposeNotCalledOnException/options @@ -1,2 +1,2 @@ -semmle-extractor-options: /r:System.ComponentModel.Primitives.dll /r:${testdir}/../../../resources/assemblies/System.Data.dll /r:System.Data.Common.dll -semmle-extractor-options: /langversion:8.0 +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/System.Data.SqlClient/4.8.3/System.Data.SqlClient.csproj From 52323d39906e765eb6bacb69fbacd7725052e33f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 21 Jun 2023 09:39:18 +0200 Subject: [PATCH 243/364] C#: Base API Abuse/IncorrectCompareToSignature test case on stubs and update expected test output. --- .../IncorrectCompareToSignature.cs | 13 +------------ .../IncorrectCompareToSignature.expected | 2 +- .../API Abuse/IncorrectCompareToSignature/options | 2 ++ 3 files changed, 4 insertions(+), 13 deletions(-) create mode 100644 csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/options diff --git a/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/IncorrectCompareToSignature.cs b/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/IncorrectCompareToSignature.cs index 0ecabd07016..5b5780ed977 100644 --- a/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/IncorrectCompareToSignature.cs +++ b/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/IncorrectCompareToSignature.cs @@ -1,15 +1,4 @@ -namespace System -{ - public interface IComparable - { - int CompareTo(object obj); // GOOD: the very definition of IComparable.CompareTo() - } - - public interface IComparable - { - int CompareTo(T other); // GOOD: the very definition of IComparable.CompareTo() - } -} +using System; class C1 { diff --git a/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/IncorrectCompareToSignature.expected b/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/IncorrectCompareToSignature.expected index 860009bd3e2..419629319a5 100644 --- a/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/IncorrectCompareToSignature.expected +++ b/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/IncorrectCompareToSignature.expected @@ -1,2 +1,2 @@ -| IncorrectCompareToSignature.cs:16:16:16:24 | CompareTo | The parameter of this 'CompareTo' method is of type $@, but $@ does not implement 'IComparable<$@>'. | IncorrectCompareToSignature.cs:14:10:14:10 | T | T | IncorrectCompareToSignature.cs:14:7:14:11 | C1<> | C1<> | IncorrectCompareToSignature.cs:14:10:14:10 | T | T | +| IncorrectCompareToSignature.cs:5:16:5:24 | CompareTo | The parameter of this 'CompareTo' method is of type $@, but $@ does not implement 'IComparable<$@>'. | IncorrectCompareToSignature.cs:3:10:3:10 | T | T | IncorrectCompareToSignature.cs:3:7:3:11 | C1<> | C1<> | IncorrectCompareToSignature.cs:3:10:3:10 | T | T | | IncorrectCompareToSignatureBad.cs:5:16:5:24 | CompareTo | The parameter of this 'CompareTo' method is of type $@, but $@ does not implement 'IComparable<$@>'. | IncorrectCompareToSignatureBad.cs:3:7:3:9 | Bad | Bad | IncorrectCompareToSignatureBad.cs:3:7:3:9 | Bad | Bad | IncorrectCompareToSignatureBad.cs:3:7:3:9 | Bad | Bad | diff --git a/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/options b/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/IncorrectCompareToSignature/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj From 82bf27c7b29361e6ab0947fe663d0c0543237272 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 21 Jun 2023 09:52:35 +0200 Subject: [PATCH 244/364] C#: Base the remaining API Abuse query test cases on stubs. --- csharp/ql/test/query-tests/API Abuse/CallToGCCollect/options | 2 ++ .../ql/test/query-tests/API Abuse/CallToObsoleteMethod/options | 2 ++ .../query-tests/API Abuse/ClassDoesNotImplementEquals/options | 2 ++ .../query-tests/API Abuse/ClassImplementsICloneable/options | 2 ++ csharp/ql/test/query-tests/API Abuse/FormatInvalid/options | 3 ++- .../API Abuse/InconsistentEqualsGetHashCode/options | 2 ++ .../query-tests/API Abuse/IncorrectEqualsSignature/options | 2 ++ .../ql/test/query-tests/API Abuse/MissingDisposeCall/options | 3 ++- .../ql/test/query-tests/API Abuse/MissingDisposeMethod/options | 3 ++- .../ql/test/query-tests/API Abuse/NonOverridingMethod/options | 2 ++ .../ql/test/query-tests/API Abuse/NullArgumentToEquals/options | 2 ++ 11 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 csharp/ql/test/query-tests/API Abuse/CallToGCCollect/options create mode 100644 csharp/ql/test/query-tests/API Abuse/CallToObsoleteMethod/options create mode 100644 csharp/ql/test/query-tests/API Abuse/ClassDoesNotImplementEquals/options create mode 100644 csharp/ql/test/query-tests/API Abuse/ClassImplementsICloneable/options create mode 100644 csharp/ql/test/query-tests/API Abuse/InconsistentEqualsGetHashCode/options create mode 100644 csharp/ql/test/query-tests/API Abuse/IncorrectEqualsSignature/options create mode 100644 csharp/ql/test/query-tests/API Abuse/NonOverridingMethod/options create mode 100644 csharp/ql/test/query-tests/API Abuse/NullArgumentToEquals/options diff --git a/csharp/ql/test/query-tests/API Abuse/CallToGCCollect/options b/csharp/ql/test/query-tests/API Abuse/CallToGCCollect/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/CallToGCCollect/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/API Abuse/CallToObsoleteMethod/options b/csharp/ql/test/query-tests/API Abuse/CallToObsoleteMethod/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/CallToObsoleteMethod/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/API Abuse/ClassDoesNotImplementEquals/options b/csharp/ql/test/query-tests/API Abuse/ClassDoesNotImplementEquals/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/ClassDoesNotImplementEquals/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/API Abuse/ClassImplementsICloneable/options b/csharp/ql/test/query-tests/API Abuse/ClassImplementsICloneable/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/ClassImplementsICloneable/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/options b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/options index ea0639b2d0a..75c39b4541b 100644 --- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/options +++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/options @@ -1 +1,2 @@ -semmle-extractor-options: /r:System.Runtime.Extensions.dll /r:System.Diagnostics.TraceSource.dll +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/API Abuse/InconsistentEqualsGetHashCode/options b/csharp/ql/test/query-tests/API Abuse/InconsistentEqualsGetHashCode/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/InconsistentEqualsGetHashCode/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/API Abuse/IncorrectEqualsSignature/options b/csharp/ql/test/query-tests/API Abuse/IncorrectEqualsSignature/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/IncorrectEqualsSignature/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/API Abuse/MissingDisposeCall/options b/csharp/ql/test/query-tests/API Abuse/MissingDisposeCall/options index 2d3e53846e4..75c39b4541b 100644 --- a/csharp/ql/test/query-tests/API Abuse/MissingDisposeCall/options +++ b/csharp/ql/test/query-tests/API Abuse/MissingDisposeCall/options @@ -1 +1,2 @@ -semmle-extractor-options: /r:System.ComponentModel.Primitives.dll +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/API Abuse/MissingDisposeMethod/options b/csharp/ql/test/query-tests/API Abuse/MissingDisposeMethod/options index 2d3e53846e4..75c39b4541b 100644 --- a/csharp/ql/test/query-tests/API Abuse/MissingDisposeMethod/options +++ b/csharp/ql/test/query-tests/API Abuse/MissingDisposeMethod/options @@ -1 +1,2 @@ -semmle-extractor-options: /r:System.ComponentModel.Primitives.dll +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/API Abuse/NonOverridingMethod/options b/csharp/ql/test/query-tests/API Abuse/NonOverridingMethod/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/NonOverridingMethod/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj diff --git a/csharp/ql/test/query-tests/API Abuse/NullArgumentToEquals/options b/csharp/ql/test/query-tests/API Abuse/NullArgumentToEquals/options new file mode 100644 index 00000000000..75c39b4541b --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/NullArgumentToEquals/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj From e85987bfc5f4f8b975634dc4ce0360a22e3c3d76 Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Wed, 21 Jun 2023 07:59:24 +0000 Subject: [PATCH 245/364] remove useless phrase --- javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp index 60c37eed8c0..d3689155c00 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp @@ -34,10 +34,6 @@ credentials in the source code.

    -

    - For example, in a NodeJS environment : -

    - From 7dfb404fd758d3633d7af1479aa1c020b1c26904 Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Wed, 21 Jun 2023 08:11:39 +0000 Subject: [PATCH 246/364] clean examples --- .../examples/HardcodedCredentialsHttpRequest.js | 10 +++++----- .../examples/HardcodedCredentialsHttpRequestFixed.js | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js index 2732e2e1851..097e9f7b1a6 100644 --- a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js +++ b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequest.js @@ -6,13 +6,13 @@ let password = 'passwd'; let headers = new Headers(); -//headers.append('Content-Type', 'text/json'); +headers.append('Content-Type', 'text/json'); headers.append('Authorization', 'Basic' + base64.encode(username + ":" + password)); -fetch(url, {method:'GET', - headers: headers, - credentials: `${user}:${passwd}` +fetch(url, { + method:'GET', + headers: headers }) .then(response => response.json()) -.then(json => console.log(json)); +.then(json => console.log(json)) .done(); diff --git a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequestFixed.js b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequestFixed.js index 5886e14d580..1747d460dde 100644 --- a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequestFixed.js +++ b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentialsHttpRequestFixed.js @@ -6,13 +6,13 @@ let password = process.env.PASSWORD; let headers = new Headers(); -//headers.append('Content-Type', 'text/json'); +headers.append('Content-Type', 'text/json'); headers.append('Authorization', 'Basic' + base64.encode(username + ":" + password)); -fetch(url, {method:'GET', - headers: headers, - credentials: `${user}:${passwd}` - }) +fetch(url, { + method:'GET', + headers: headers + }) .then(response => response.json()) -.then(json => console.log(json)); +.then(json => console.log(json)) .done(); From 34e50de76dfaaafeb74100c39e3ca8a136e09b8d Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 21 Jun 2023 10:39:52 +0200 Subject: [PATCH 247/364] C#: Only use the dll's that are strictly needed in the API Abuse/NoDisposeCallOnLocalIDisposable test case. --- .../API Abuse/NoDisposeCallOnLocalIDisposable/options | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options index b8a701342a7..a02c94f4258 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options @@ -1 +1 @@ -semmle-extractor-options: --cil /r:System.Xml.dll /r:System.Xml.ReaderWriter.dll /r:System.Private.Xml.dll /r:System.ComponentModel.Primitives.dll /r:System.IO.Compression.dll /r:System.Runtime.Extensions.dll +semmle-extractor-options: --cil /r:System.Private.Xml.dll /r:System.IO.Compression.dll From 0edd80001b7d8c3b5bdd054b295792398b2ea9fe Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 21 Jun 2023 09:32:29 +0200 Subject: [PATCH 248/364] QL: Add tests for `AbstractClassImport.ql` --- .../AbstractClassImport.expected | 2 ++ .../AbstractClassImport.qlref | 1 + .../AbstractClassImportTest1.qll | 4 ++++ .../AbstractClassImportTest2.qll | 8 ++++++++ .../AbstractClassImportTest3.qll | 18 ++++++++++++++++++ .../AbstractClassImportTestQuery.expected | 0 .../AbstractClassImportTestQuery.ql | 6 ++++++ 7 files changed, 39 insertions(+) create mode 100644 ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.expected create mode 100644 ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.qlref create mode 100644 ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest1.qll create mode 100644 ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest2.qll create mode 100644 ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest3.qll create mode 100644 ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTestQuery.expected create mode 100644 ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTestQuery.ql diff --git a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.expected b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.expected new file mode 100644 index 00000000000..d2dc19e467d --- /dev/null +++ b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.expected @@ -0,0 +1,2 @@ +| AbstractClassImportTest1.qll:4:16:4:19 | Class Base | This abstract class imports its subclass $@ but doesn't import 4 other subclasses, such as $@. | AbstractClassImportTest2.qll:4:7:4:11 | Class Sub21 | Sub21 | AbstractClassImportTest3.qll:12:7:12:11 | Class Sub33 | Sub33 | +| AbstractClassImportTest1.qll:4:16:4:19 | Class Base | This abstract class imports its subclass $@ but doesn't import 4 other subclasses, such as $@. | AbstractClassImportTest2.qll:8:7:8:11 | Class Sub22 | Sub22 | AbstractClassImportTest3.qll:12:7:12:11 | Class Sub33 | Sub33 | diff --git a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.qlref b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.qlref new file mode 100644 index 00000000000..4d7907c36ef --- /dev/null +++ b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.qlref @@ -0,0 +1 @@ +queries/performance/AbstractClassImport.ql \ No newline at end of file diff --git a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest1.qll b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest1.qll new file mode 100644 index 00000000000..ce7f7c4ea68 --- /dev/null +++ b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest1.qll @@ -0,0 +1,4 @@ +import ql +import AbstractClassImportTest2 + +abstract class Base extends AstNode { } diff --git a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest2.qll b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest2.qll new file mode 100644 index 00000000000..df29a5c18de --- /dev/null +++ b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest2.qll @@ -0,0 +1,8 @@ +import ql +import AbstractClassImportTest1 + +class Sub21 extends Base { + Sub21() { this instanceof TopLevel } +} + +class Sub22 extends Base instanceof Comment { } diff --git a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest3.qll b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest3.qll new file mode 100644 index 00000000000..d2917d9aeb4 --- /dev/null +++ b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTest3.qll @@ -0,0 +1,18 @@ +import ql +import AbstractClassImportTest1 + +class Sub31 extends Base { + Sub31() { this instanceof Comment } +} + +class Sub32 extends Base instanceof Comment { } + +final class BaseFinal = Base; + +class Sub33 extends BaseFinal instanceof Comment { } + +abstract class Sub34 extends Base { } + +final class Sub34Final = Sub34; + +class Sub35 extends Sub34Final instanceof Comment { } diff --git a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTestQuery.expected b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTestQuery.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTestQuery.ql b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTestQuery.ql new file mode 100644 index 00000000000..f15c7fafb43 --- /dev/null +++ b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImportTestQuery.ql @@ -0,0 +1,6 @@ +import ql +import AbstractClassImportTest3 + +from AstNode n +where none() +select n From e6e966bd229df063892670eb3114e231f3655d3b Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 20 Jun 2023 15:44:34 +0200 Subject: [PATCH 249/364] QL: Model `final extends` --- ql/ql/src/codeql_ql/ast/Ast.qll | 5 ++ ql/ql/src/codeql_ql/ast/internal/Type.qll | 59 +++++++++++++++---- .../performance/AbstractClassImport.ql | 5 +- .../AbstractClassImport.expected | 6 +- .../MissingOverride/MissingOverride.expected | 2 - 5 files changed, 61 insertions(+), 16 deletions(-) diff --git a/ql/ql/src/codeql_ql/ast/Ast.qll b/ql/ql/src/codeql_ql/ast/Ast.qll index 616438da756..19cf38c3f1c 100644 --- a/ql/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/ql/src/codeql_ql/ast/Ast.qll @@ -611,6 +611,8 @@ class ClassPredicate extends TClassPredicate, Predicate { predicate overrides(ClassPredicate other) { predOverrides(this, other) } + predicate shadows(ClassPredicate other) { predShadows(this, other) } + override TypeExpr getReturnTypeExpr() { toQL(result) = pred.getReturnType() } override AstNode getAChild(string pred_name) { @@ -878,6 +880,9 @@ class Module extends TModule, ModuleDeclaration { class ModuleMember extends TModuleMember, AstNode { /** Holds if this member is declared as `private`. */ predicate isPrivate() { this.hasAnnotation("private") } + + /** Holds if this member is declared as `final`. */ + predicate isFinal() { this.hasAnnotation("final") } } /** A declaration. E.g. a class, type, predicate, newtype... */ diff --git a/ql/ql/src/codeql_ql/ast/internal/Type.qll b/ql/ql/src/codeql_ql/ast/internal/Type.qll index c1aaf84d8c2..2053c657904 100644 --- a/ql/ql/src/codeql_ql/ast/internal/Type.qll +++ b/ql/ql/src/codeql_ql/ast/internal/Type.qll @@ -21,7 +21,7 @@ private newtype TType = private predicate primTypeName(string s) { s = ["int", "float", "string", "boolean", "date"] } private predicate isActualClass(Class c) { - not exists(c.getAliasType()) and + (not exists(c.getAliasType()) or c.isFinal()) and not exists(c.getUnionMember()) } @@ -36,6 +36,10 @@ class Type extends TType { /** * Gets a supertype of this type. This follows the user-visible type hierarchy, * and doesn't include internal types like the characteristic and domain types of classes. + * + * For supertypes that are `final` aliases, this returns the alias itself, and for + * types that are `final` aliases, this returns the supertypes of the type that is + * being aliased. */ Type getASuperType() { none() } @@ -94,9 +98,23 @@ class ClassType extends Type, TClass { override Class getDeclaration() { result = decl } - override Type getASuperType() { result = decl.getASuperType().getResolvedType() } + override Type getASuperType() { + result = decl.getASuperType().getResolvedType() + or + exists(ClassType alias | + this.isFinalAlias(alias) and + result = alias.getASuperType() + ) + } - Type getAnInstanceofType() { result = decl.getAnInstanceofType().getResolvedType() } + Type getAnInstanceofType() { + result = decl.getAnInstanceofType().getResolvedType() + or + exists(ClassType alias | + this.isFinalAlias(alias) and + result = alias.getAnInstanceofType() + ) + } override Type getAnInternalSuperType() { result.(ClassCharType).getClassType() = this @@ -110,6 +128,12 @@ class ClassType extends Type, TClass { other.getDeclaringType().getASuperType+() = result.getDeclaringType() ) } + + /** Holds if this class is a `final` alias of `c`. */ + predicate isFinalAlias(ClassType c) { + decl.isFinal() and + decl.getAliasType().getResolvedType() = c + } } class FileType extends Type, TFile { @@ -136,23 +160,37 @@ private PredicateOrBuiltin declaredPred(Type ty, string name, int arity) { result.getDeclaringType() = ty and result.getName() = name and result.getArity() = arity + or + exists(ClassType alias | + ty.(ClassType).isFinalAlias(alias) and + result = declaredPred(alias, name, arity) + ) } pragma[nomagic] -private PredicateOrBuiltin classPredCandidate(Type ty, string name, int arity) { - result = declaredPred(ty, name, arity) +private PredicateOrBuiltin classPredCandidate(Type ty, string name, int arity, boolean isFinal) { + result = declaredPred(ty, name, arity) and + if ty.(ClassType).getDeclaration().isFinal() then isFinal = true else isFinal = false or not exists(declaredPred(ty, name, arity)) and - result = inherClassPredCandidate(ty, name, arity) + result = inherClassPredCandidate(ty, name, arity, isFinal) } -private PredicateOrBuiltin inherClassPredCandidate(Type ty, string name, int arity) { - result = classPredCandidate(ty.getAnInternalSuperType(), name, arity) and +private PredicateOrBuiltin classPredCandidate(Type ty, string name, int arity) { + result = classPredCandidate(ty, name, arity, _) +} + +private PredicateOrBuiltin inherClassPredCandidate(Type ty, string name, int arity, boolean isFinal) { + result = classPredCandidate(ty.getAnInternalSuperType(), name, arity, isFinal) and not result.isPrivate() } predicate predOverrides(ClassPredicate sub, ClassPredicate sup) { - sup = inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity()) + sup = inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity(), false) +} + +predicate predShadows(ClassPredicate sub, ClassPredicate sup) { + sup = inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity(), true) } private VarDecl declaredField(ClassType ty, string name) { @@ -376,7 +414,8 @@ private predicate defines(FileOrModule m, string name, Type t, boolean public) { exists(Class ty | t = ty.getAliasType().getResolvedType() | getEnclosingModule(ty) = m and ty.getName() = name and - public = getPublicBool(ty) + public = getPublicBool(ty) and + not ty.isFinal() ) or exists(Import im | diff --git a/ql/ql/src/queries/performance/AbstractClassImport.ql b/ql/ql/src/queries/performance/AbstractClassImport.ql index abd00689909..24e05860f0a 100644 --- a/ql/ql/src/queries/performance/AbstractClassImport.ql +++ b/ql/ql/src/queries/performance/AbstractClassImport.ql @@ -38,14 +38,15 @@ Class getASubclassOfAbstract(Class ab) { /** Gets a non-abstract subclass of `ab` that contributes to the extent of `ab`. */ Class concreteExternalSubclass(Class ab) { - ab.isAbstract() and not result.isAbstract() and result = getASubclassOfAbstract+(ab) and // Heuristic: An abstract class with subclasses in the same file and no other // imported subclasses is likely intentional. result.getLocation().getFile() != ab.getLocation().getFile() and // Exclude subclasses in tests and libraries that are only used in tests. - liveNonTestFile(result.getLocation().getFile()) + liveNonTestFile(result.getLocation().getFile()) and + // exclude `final` aliases + not result.getType().isFinalAlias(_) } /** Holds if there is a bidirectional import between the abstract class `ab` and its subclass `sub` */ diff --git a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.expected b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.expected index d2dc19e467d..952a49efc65 100644 --- a/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.expected +++ b/ql/ql/test/queries/performance/AbstractClassImport/AbstractClassImport.expected @@ -1,2 +1,4 @@ -| AbstractClassImportTest1.qll:4:16:4:19 | Class Base | This abstract class imports its subclass $@ but doesn't import 4 other subclasses, such as $@. | AbstractClassImportTest2.qll:4:7:4:11 | Class Sub21 | Sub21 | AbstractClassImportTest3.qll:12:7:12:11 | Class Sub33 | Sub33 | -| AbstractClassImportTest1.qll:4:16:4:19 | Class Base | This abstract class imports its subclass $@ but doesn't import 4 other subclasses, such as $@. | AbstractClassImportTest2.qll:8:7:8:11 | Class Sub22 | Sub22 | AbstractClassImportTest3.qll:12:7:12:11 | Class Sub33 | Sub33 | +| AbstractClassImportTest1.qll:4:16:4:19 | Class Base | This abstract class doesn't import its subclass $@ but imports 2 other subclasses, such as $@. | AbstractClassImportTest3.qll:4:7:4:11 | Class Sub31 | Sub31 | AbstractClassImportTest2.qll:4:7:4:11 | Class Sub21 | Sub21 | +| AbstractClassImportTest1.qll:4:16:4:19 | Class Base | This abstract class doesn't import its subclass $@ but imports 2 other subclasses, such as $@. | AbstractClassImportTest3.qll:8:7:8:11 | Class Sub32 | Sub32 | AbstractClassImportTest2.qll:4:7:4:11 | Class Sub21 | Sub21 | +| AbstractClassImportTest1.qll:4:16:4:19 | Class Base | This abstract class imports its subclass $@ but doesn't import 2 other subclasses, such as $@. | AbstractClassImportTest2.qll:4:7:4:11 | Class Sub21 | Sub21 | AbstractClassImportTest3.qll:4:7:4:11 | Class Sub31 | Sub31 | +| AbstractClassImportTest1.qll:4:16:4:19 | Class Base | This abstract class imports its subclass $@ but doesn't import 2 other subclasses, such as $@. | AbstractClassImportTest2.qll:8:7:8:11 | Class Sub22 | Sub22 | AbstractClassImportTest3.qll:4:7:4:11 | Class Sub31 | Sub31 | diff --git a/ql/ql/test/queries/style/MissingOverride/MissingOverride.expected b/ql/ql/test/queries/style/MissingOverride/MissingOverride.expected index 915a92c85f5..d64a6ed1544 100644 --- a/ql/ql/test/queries/style/MissingOverride/MissingOverride.expected +++ b/ql/ql/test/queries/style/MissingOverride/MissingOverride.expected @@ -1,4 +1,2 @@ | Test.qll:12:13:12:16 | ClassPredicate test | Wrong.test overrides $@ but does not have an override annotation. | Test.qll:4:13:4:16 | ClassPredicate test | Super.test | | Test.qll:18:13:18:16 | ClassPredicate test | Wrong2.test overrides $@ but does not have an override annotation. | Test.qll:4:13:4:16 | ClassPredicate test | Super.test | -| Test.qll:24:13:24:16 | ClassPredicate test | Correct2.test overrides $@ but does not have an override annotation. | Test.qll:4:13:4:16 | ClassPredicate test | Super.test | -| Test.qll:36:13:36:16 | ClassPredicate test | Correct4.test overrides $@ but does not have an override annotation. | Test.qll:32:13:32:16 | ClassPredicate test | Super2.test | From 27ee4241e815f1e78e50f78d1135fd78d82c360f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 21 Jun 2023 10:45:08 +0200 Subject: [PATCH 250/364] C#: Remove unused test assemblies. --- .../test/resources/assemblies/System.Data.dll | Bin 200192 -> 0 bytes .../System.Web.ApplicationServices.dll | Bin 13824 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 csharp/ql/test/resources/assemblies/System.Data.dll delete mode 100644 csharp/ql/test/resources/assemblies/System.Web.ApplicationServices.dll diff --git a/csharp/ql/test/resources/assemblies/System.Data.dll b/csharp/ql/test/resources/assemblies/System.Data.dll deleted file mode 100644 index 070caaa81f33de941a876f4e9eb1ca0b1dd614b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200192 zcmeF)2Yggj*C_nG&zy5e!ptO-GARQ{lTHXF6zQRg^d1ZldM}}q&Xjp*Ai+TjQ&$z8W?B1B7R6SuD#UwTLTLKH7rP{s&h z!puyov}sA$E(+TXaJC|dwl!pFfE|o4VolIj~YFy z4;0YcV2-q-e(>t^rvc19dQ`umBcLMARluC7FZ)CF;(VIXW*J;p_=9uPgdwK2g?&A) z34bch4_#sZr{(icw~A zf#$OQ>AF2IEuWpG{kbpP2XD>%*GJ9ougV@8+S`?t@XFhTw-l|KdXx9Rsx)l;c_zQZ zhpOG*=uv|8^*Mi_11Pxv((cnKZ9?$AdUwG4>QmLHU)cQ3VO{a*)#~7Z=+ngmnSX^a z^drwY=#vI~AUrVCUu6Goy7%Yv7oG;r=l#{J;k{Y!9DSO2i+rkBZB)d}gFBtyN>%gS zc+?zJ9{Z#Ayg}Pm)@Kr`jyD5S@ZK%F-E$pp2R=2dM&3kzecFP0e|D>+^89AJ>wor8 z@lVSS<8uv+`e(1+vn79?Fa@X&kFwP6AH8~K?ehwoK7tPaZo=LLwi^00{|9aVu5a&7 zLa+aZ-n?(%Jbw0}*MCpf_fOQTe=z4idwad*w7T9S@b8w3@~}hy`~ZL%{^fyUy`3ul zgB==Bz&if!dsQ9$dpGhg2LIlE|Ha<^51rOO+^c^ydpHp2$o#WcHJ11C^j8HuqI&tC zcdB}a4eW+SRWH8T|MWHw`kx-=KidEQ9sBV2vxMVlK40qT^^uFlhl-W+9<5yHiIF0J zzsWdXKr533y`3#5goJA*eifr>q5!7Na_-O|NjFaD2Pfw3=#fMID~12TuK$&3J+kfp zO>_N!JK#NhAGs3$wZi||F#~7#ea{(x=l|Mn{MkVNv)%i%Uj9ER|EE*`i}%3$0RCsM z^wkTrzwg!BStxzv1INQlf%B}ch2kG~nPK=e`v3GlUx`0kZ*MuQ`@?rmF2Q%;{(l~R zmwZdSeg56+ePi-i&}IRDMd#b)166T0P&3O3N5ccv9$<0JUFHIQOZ4ytHO1l|F%Rva z$E$dJSzY{%yhm>Ue+BiIuU3!L^P>W!|GF6W*XrZp=#%l;e7N3UlyLX3$F+EG=oMN# zYFb?OS99_mi>gD{3EcI4uihcNuiia)@YU+jTk4}n%mRzN|9ETOSB<*KFM+vD1r z!xr@O(AC8n^}l{S;ptnW|F^CV4?kL}5|{|R$G(r5RPax)Al?hZ{Z|s}{j&}{SpEOh z<>8^jGymxL4_y`hY{dK>&foH>n?J9=xg>bo{3ovf`IGtcbD!&2JM-^~k2;^B??)Bq z&+%V4&7tG}-=E-gK>42C|MbMZ|AfZ(gRZg*`3r7(g*T7-|LZ`tya%@T^^wQagGU{_ zfs1%NdcAKv)q}T|RggayRpG&A*3NjV|H+K3O1@RS<2?B4?Z`WfWfi^E|Ek)3llC1G zw^dJSM9kL;EA!KY7}oll!bZ(5x}Gw(gd z`_Pa-2Q{8g57ar2aQ{+Twey$s{zj^=M{cMK@^riP5rkf8nE$QdZS=^&9$Bb9s8Unj zi-&drmTNJeGJpB%+X-zyFeY9ymhcx{`Rkp(1=V4w{IfEDRUhc+Z|Qx5|F)v4;BE1D zuT}%PY%S$A`McNr9fHRBd&^rsd#on&s7l@gRaJrw?_}@a^sV8$4Yil?>fb*ot}~SQ zJkQbueB1Jj?yL8}EUoHP2%XW_<5c~ji9`0GGT*WO``fqx|LQ;1tYP20Yy80SF#om! z^pjte*2%kG|E<^m{`&v(5n&DL23lWN`>wBdX=w3$-$_X1zaRJE;dS<%g-_M|ijUg* zCly6phZb>CNct%}{@sOf)uLmftHxBVTnmc~F%)9g15%WLUw+Dk*MZLnQKG|`QGzY5^w#LFM3m^%LBzmz5R{c@*6GQ{@Y(>pawIrz=!o7}8UDb}^<|fyJ8b^=7e;=Q zRfQW0U~?DzTNyTXLxlr@LUf0Jw?P>!k;sN}C;T;u;;Ls=6;h)Bp| zAFxUP3h`b;H2&q4YSHPVOc7u1tE7VB_$Vy-H2Qc`Q>0h=x}z!HipIFDBF0-4Fuqc%&BBsF<*_8Q9F|muJ#~sJ z(O9w$>Nv%b0a*Utg2j_f@paEL?M!iL5ylJMvF#>kk|o zpNQF-Nf_OoFa{09*qTauQ2eknj`c(g_IVk$onquHjL-Ygc7KfHVQvA!R_RtdSi_39 z+BwDMP;Au|_BTN6jKcC0+EQ4_mV*z*ImIv4u+?*IvCfhxT!$3{aaOrK^Pp|Lve?_+ z$FY8B+EQtXxLAB2I}gTpq?^F^F}Kw@GeC5hg>_aYVgIX!;eHDPCw6A8U#krSK@)+Z%g(zYQMS&z8aU z=|kJUL}IxV;VDirnr6~pEY(f;TUr=9)w-}USj_0qdX!rn={Ons`D_L5#V|So%ToN2 zVkotZO~>9Ymc+AcPg#tsDK3r15vP|;ALSH9Xs@H^;F`>XbHNlFM&b;c_Fb^Z6l>dH z&4dh`=eLz``&hz2XcgW6HQ2``aDJJh7rnDFtI`_a)ub3*RPbsk;X0(l89SD?C6pH} zlwex}3KFQ*!%#ZwSV@$f)$VCj5bNbKs8G;!_;=3S1ly~^L%ASPpi6>HNRNmVvS^T4 z+C9Nm2XfIgN|WXZwhN#tq$3j(YfkG zcGh?^X!NhS=1R)VUSj38Q=e5k;54cJTK-S(ox<`?52GfR|?mxn|OzE^Eh{a zbdT5NFzx%$hIoW@6UV5}jWw{(-mG%8x4p$lSa~51)4ADOoS}9l>1^zWf?V0hv6n$8 zSlt^F@VFk%HDBtFN6&C^p4#1Ok2QyjFKI4s)67Pp;N7fAxl!UG<*vX8b;NiSyzeLI z{2MPWQ_U{%*vokFJt=t{Y7z=o;zc-f!n7Hz(=@^iag}m~Y2Rmv>(s7pA#688+$3d% zq0(8=B~Wu%->0JHvjXU-TSN*HyXYFSjdL^TEZ!z=L!UvSE$8mi2!WjYgS3j)Y@4v@ zIO{iPW;g6E?a@x*gj|qlKu7CN5vJn`ei4fE+$l;Y@#1YKF%D?e+_Sie}h$y4`gWg?{ zJ+`oRM3g7hYlb=se;XKcyJAqs#cXPKXk7N#SH&mdebTt8mc9ZBF>Olr*fo&*o!UKD z9NV2|)vk~FT9h!b&k`QgcVdKr>-lw~?6Hf*6|sSGPdhMoMeHM)5_MI4O{yVK*Tv%| z_VO0#rsz+4FB5aWiH#=i-wU*V_ryg@3AnfS#CKG)KaGA*{6Na6h3zz1q5!s=L^b_o z-vYS0LqHDcF9#IBcctQ>?6Dg_L#Sp`nDwh7K#nYc?@@di-1h*P0)nHpC9JjPWG!!H zX%gl7b8a$e=~Gs23hB!hmZp;0aBdo@6t|mBn#GzyYRx0eB#q*BsU!#IW|5xd5zNIbK`lkuu3!kSpqQVxx` zq?0G3l~zRVr(SkV!Cs2U6OQ1U5zb`Nyj->$5tD>g7O5>#ldNS;KP5Bck2XaB6 zs(!fd^XlNtYRYz?An{FCPe!O-mn6g%%GH(Wlq&`+5urC=>Gg4h2J$@RZV&Nf6oT9Z zKRl9idU-O+fC~6a87fZ3S~XjOg2d|OmRkAa`S9{^OYx*Voh|htT}bd`)P!D!P`kAg zJsEdlyzw9*2GBd!Ku+?<@p>m)xoMR9uqW(1SqLNE^B)=%JwI zq(hL40QD#34N1@ofs#pmdnM>)K&wcnMkMGs!aD)D@=p)9^d4zhXG;f3X-_BUHKE-{ z)UMjf1idThW75!x3Hn{pPo4w8$KU}8a4+a5zaqWWAVFUPxo-oe!ybJ+2K$`F8cSLL z!o6KQC_!(mFJZNW(VK$;3gXPBwMo#6f+~|LS4hxHf@&1Rc78DWP*81<5O4R#(U-`& zlnYNz&__b9A?0iXtz1*eRfY9@RVU*lFUcgz6&+~h#!;?X$MLY9mt->KdX^jy>v>5|Cq3D2ZV&jZrh(v0 zy)$HPkJmIE1@jzGb8e4p&_>d@PL^IH<<+qCDJhO~-`Mf$cEVxx65v2h?PIAHDXXic z1P6|H6mqW$U7JX`gE0Cno33R!rWXwrBihXE(MdD3^PnIRUSV#JgP z+Tg-o3@yfq<6RnIsf!awIKzr}VlNp_&+Ty(+9f*iJvueUs@ab;ffS&DpxsM@aD-S^ zo6eS|Q=i}V!*;RSI%+p}w59cwGy7Y5iF#?b(o&Wa-&hh(_Pg97m|HeL~73wFP0HrKV#qJy6Aj zxE&NZY>nv4Ip-|Y0MPUBboh0($YDYZp_)M=p?l;oha94vf?k5e?M0EpUWMFeG?&+1 zmOdwKj*cAG1Zq|Z#OI|06)e>a#CBtBR?U`yxbK_GMh;u8578DryC5n~gCd5u>pJ%rKVGy#l?RM}7D`sN z##mzXv#R{tW^17&GXP_FZH&Ly!PvS6#-AbUoylqQ1t_T(jJ` zpEb4y7~=Ek+f^N{z)r|kPsKQ-AjYn9Fg9+0@l0`yI%RYGcB)prYwd>ePwQelu>xb4 zW*85}VBEYMrjH{brTsG&J%2pV05=u&z!Z@z(NmYK@JPjqs zmSe0i0%OTir&V_JqVrHPk>V7J?^HgovLW`bAUnAM#yAsWp8$+0WxrB&Ziilik~76I z&YX>LYuqK3JtnU}$v%kQCxy{Rr1;FJ5X|B1;)YY7|Zv< zxUMwDJ;gC53yiUp?NJ}M%gn-fB@E*|>LD)^w{In4d}a~Gg4EB2dbmB3`uUD(K1VfE z0!|H-R3|76vwQnt{E+4rLA{w7Skj}>9X0}*kMZa%jFDwz zLGL>Bt7k&VUKhqQ#WBvDW~yxQDg~irXaL3^XJWjuq@c?7NDP7!dt;10W?;M~F<#Oz zZlmoD5WQpB8;4OHi~(9$!RjJ6E(&7z(vQ(L#!ri5>{|t6r$mfem68y5R>qhchp|&) zN!6$Sg0j$Cs=&Co6voCSFm4IPxVJ9GGsVkNKhe|=#@slJ9Aj=A#!iVCwJIH{9Aj=A#!iVCwJPycjxje5W2Z!n{tIyCsRHBTQWzVTz_=wC zznR|^e-ssz3l@D7n1WG!W9imFM)EfyUJrXg#0NdVo zb8zffC>cZXl;2oYem)=>%2R?d9`?i72e!SfewZ{BN}A2Ym^K^Z;i(uOTZM5`3dU9S zF!t&=751)bXez|LllnmXcr3=jsTfyK$@KBKoiPn#H!3+qb-Ingk{4(|LpGk?Q>0c97ck^z28p=9h}j5W$)+?MS0HVMc0!4!-?KaMeaCB|!^7=x*P)NI^7QyOE_o){y`ELG!{%UB5| zPwE(pmd1FCN^1AO?X9ygmL7!h8!A8E6u0{T=u`R_^#rHVDqoTSv*Z|`>imhkhc3KIH?Wev1al-_RKTgMZbOy#b5g7YT#<+J9#?o$# zuF)84)Ak=>xa}E*v2F^+W~msbkH^@L>U5`)Lu0X|AoU}r;r3Hh@;QxlGYLyN=ol|h zZ>OlF+ZZgF+Y{q%swrsnt&|-}bNhzo@FTU_Hxb4W*Ac? z#`3)|ZeEUYU1^M&6bBW@?PZA=d(_9+$V1z!Fjg3W@dK(e+=1Ie>tbx&4`Y*_7?03c zq1699>SwNwDLDbuKG^^hz9;cW`@dCx`6hEYXBB&pe+RnE6p%Mck9@RS`{_hv(3 z_Ch_}9!YJ#qnaO69eC1%@^#eeH!9!T4@*9z(IcR(cUJQpd!gJuALGfwc*H*24r4dE z`n^bJfi?@s*B%&i=!)8g&Wp>G?cEy7U$A4GM`yv8!*F|jDU2Ub zt0_^qomdy+swx;iejKB%9>y{e7zOoUP@N~JzM%M2IA*``$N26tj8&Io^iV4&#lCb_ z=Ft52%);y+G|w++^cpnEbF^KgBxYCB+}@{>c`oX$C&ukmQffMGpDvRBZg#4>A66{0 zA;u6p#-=?no($Np)^<~sLr}7oV$+_7pojQ4?5ERX7z-7~_&dcRRI<80mRM_Rty@|E zmi$QT*)S8gt<`8nD>jK%Y(NVvm$cWjsib%TESZsrQKz1#z`Yypdi3s8pzUXBV#zO+ zF}7-h@%0Rh&osk0WCg~TY20Bx$MBA!$6$}%8i?_2+CEbpx8H|t?-6yT_(>>w1>ObfC3QB&>#CRYU=lWze?N=^24SqZ1Y;`IKSN_prLk(v!tya7ROuoBI1EscJh=2mq+)+z76*oVsBrSix! zUlnXy6uv?cX%Tlux`h;7l`a*OBGHmx&9tipHPMHZC-#Qj0QF~8&bVFBCI+$UglcwE z3?=1?nj`$}1;hx>6*OITKQW4wCe|;Bu=|U#ocpmzQG0-xz_}I~rR@bp3g?=cmF#vg zS*g0+A*L$1gi}mc$`OHLCMlKnC`in;a{lSX;^Et<1*~U^xj>6ZX?|-**R{KZ^(W6U zE}{`=Ddlqg%fr6AL?$U!ytK+KTw*0@mKc+E33AVn@qqdin?;oOh{-9Xz|(?Mb4bxY#3*~{)0JCp|4!^JM8k@hI@ zrc$!Ku-K!NYA-7Gvc7aLvX>C=vO=q_u$L73SyvL>;&E|+rA=C6e_R}5rS@EJFC~t! zo`~ISFC&gAZL^mZ$5|7r_Oh1~CzV{Hy!eE*ELDmM;*=#?rHbMU624=NWJPgF8-v+6~8kqQ*y}qcznv&R1)ECuQiBHFi z2BHRQ=+iDxEmEF;qnhXK4MiPRrT%6dkHw2P(U2AUm!366*V8g_5i;b0f2FROq3a`H(rfHiJeym(R!W=&t_0u5ya zt;iBB#0Xa56?RaPw;i0RPl++C@>R0LQ(`=;dKEipB59V`73UT$MG7fZG^~P}Ov;s6 z)$iC_im6<4Np+WKC8m?oL|6kUT8o(^>kMxr(ySaDbv8#EvA~jFjplYod$E{R0#>)Z zSjLKl)om{_S!0&C93Ak$6*lX-tCS~4gcovj;#{5_9A3iFMJX{n#__aRMZH+pmjv-V z_j$8P4M&1_QK_z@yVyvwt}i{rX3pXDrH6Qhh1Zv!Vv8lXzStd!;x(m4pzTU^9lgX( zr6(P|#T!cP9eu@HtS{XOjsfCrR%q2ej)7ty3$HJO#Ct5fz6=t1tkj-^9D~LCtS4fV z97DxnrET_M;se&is*N1O#fM5RF+vrC41SRzWZ z+RfbuD#!W_j^rhxA`9=gOGFIGx;rfqRXJDGo+Xxu>a6l`XIvs`vWCD2OGRzgas~z3(GDRD! z9j$dH9j!v-Ic_#N>hRSG#|qJfYNq+&F}PC1v+x*PC7!nWl<*z0;~CLI=}X6I(aWj{ z$LAHtbE1#R-EgcG{gv)I){8+(e$JP~P^D1kCNYAPD`lxGj#otz=e~3ob8Zo%S)oUEquMLH=>Ossmvu}fqqx#0grVlE4h>o>%FZs!mC@TOQunguK0$hljr zuxk2==~?jmMbEHqHhI$dmRQ3&*tCsvk65d6ot^K9^-78L!`0@C}e&C@VIf^1YJR{vJu@A~`$%b_ z^8;~GX_fOs_|BTnesOx{I_F2?GuCgzH#tv;b4pvCC&d>^-Nnb^E7p$TyB(j1i>zZy zb~rx~-zn{Oeky)Y%5|O=KPnw^ekQK7%A}?{&x&7^7CO&~TS}{(pNrp>);Yfr_gGz8 zA9sE!WC?2@vf}zUz7o39Dd*RsfYKMviy}a2js08UVD*8Oza#=#f0!s2%YVc-&PyUh z=?CX!5vEiPev3Gq^|hZ{TosX|RIxR#k>jfHaPI7q>&_oVVWnHnYvM7Ib;r9dN?SQN z=0)IjQOS~@tG!>~&!P$o@3249x#_*bdWCmbN8nA);T<+K@RkzZVeg1opYiUBx}-e6 zujiJN@H;|0!p$bd0`H1Omf*T{-FZ(mQ7RqyhiJ~iYlx67SlXl;pjJxJ@blibq&&Q$ zNKLlqTx!p1fx7I-x*Aj`(3D-2N(UB@-MHPXk=3Q2?9RC-V&ek+WFl)#YV$yU*_$=7 z>UC#9*_VY^6uazCvR2n2hg&(nTZ`KSI%E>-h4d`pkYiZ07Nf?qZZ`Q8l*~HV^ep`5 z+a#6i=M0ilRc^4;C8x9SJqnSjtd!QB0z+gv>4JZS;qf9w&S9lD=?O7=aeP}M#<+{c-1H* zUm#tSc-1H*H<0qgn3Nl!ES6tbIaye~Ou8T&jO#55%Pp*zipGOpW3_d92?@FBXrPCB?|kBF6^Ko))qDKCRr_$j2k3}xZxjtVlIg`Ybr$VirB^4h?PvJh*3 z>WiSqSf^4qgNl*z{0D@+78or{vSx({++sHi5MA8 zO7n{yb2u%P3TkT|x*=|uy z*5w>tiK@x^AU}~OuNS{su$qkH-193?O;{UyeI8g%Hdp!v^b{#otPQ&w7%N*V{T5h5 zwj*7Xm0-M@vIDnE8hy23P1#w=7F1KllQQ9NF9ZbDk_n`|hQWFx`Go92%9ZP)UKe#_ zFB04zY>i|c*@u)So^BK`>dF4B4>i;vR@c#4prJ}3LG|Pa);=vVsJ={6Djw8Oj#erk z)JTq1suI*hjwj{HwrOtBOim=Fil^-AQKl(fD%eHNR+<*nRnAdL59%i8DJ>4_E*B`R2)fKm2$)wnM2Bz z2cmMsSotO?PvUdPIQbUq3cN?-`{^*XFls{BH!h-;SoQt9`gbosSXv}?A!sN@oJr9Iw!Me&2VG7wcsKl65CpF9S)| zon*ZXS2>q>Q9hB^*EzzB1qb$e5JIO{_f#rd#aF(pZDm-baD@#^k{W@bMD3*nv znX_a~R@{;{(5^P?4t$@LCF`+*+qggtSonR`CfSIEcbQGHDapFaY?4oM4(~FXWJ?y_ zWj4vytf?!@$<4AIYw1cUHp>nyyaT-~JG1Z(^s?;AY6koFihP=d_oG*24;J2!UXh8c z4w<_hugX5G-kAxYek{B@ZIJ_6cz4<&2eS^$T;tj*hmrE=ezaANWa0g2s~knL?nm3? zSZ=qeaJ<+iC$M%Ec7c*v)e5Y4y(TBInu1=JQ&<;b*SogMX{?_?JLC+Kbyv%lsVuy! z?UZR;vzA|$YnPnOY7WYgb6CBqXSv>x^H@osH{}9WlY&{U-EtADBj_!;gjKwDmTQk( z#;O8(TV}Fs0b5+}$d#;6&|dirE34)f*FL$L^(N?D`5eo>G~4x_T*oQ|%9ZOa(cO2y ze36t#ci;W;CC)9kxy62&#lm~>ez}=zUN7FrzF)q|xhXMkx%SI#tmjuWvLBG!S$JnY zAa{cNM6N6tin%u^mq&Ns19CUl%z*I@$UUs2(O7e@(z~t$@;y=}{O))_(EBovbI$1p zT?gesl67Z3C=ZizW%lFW+YieRSWm$9^RWDg+i6R$I}ghftY+ph*Ae-#(kHH?@>3Gt zDZg+XlczbCy5x%MxIC-$i|eHPoYf?JanL97g3=$ZPvuuiD}qkTZ&=lrx*TWaC6J$( zCB`l{gU`zEDVHld_H_iGlUGUm<gE>}{H46bO06Ch{FVHT)xTg=@YnJVt4Zys;BVwTR+)gJ!55_{g;&g6d8}s9;BTeI zs2T2Z(xG%V=m#0Z!h7l!8LU*@epQAlxx|mst&}6K z$q15lPyIcPLrawO}1 zdrMYi;r;fOjA7yZ_Li)|!u#!QS&d|U&;FaNL9*_?zsXuk4TFD|wUvGfx-07{JsJFm ztgrNYkft?M>KJU(8YyWmLu;ax5L`fOrsNU<+LKC0MM3Q;CA-U^wNe@o9H_NXdPf9n z?UY6ahiDy?LS126C#4C&;aV3K-tD8bc%_EH9_?wR--8Nk-IY297twkuxkOQ|m(o#D zOzWfcjwqq^QyLjuQX60i?)Hm=N@*i3`QdkKrL|Ekyy}9Ss%i5$ zhu;}j(-yGsJL6bw5zAA(o4vZWgjEGpLtADEzME-euc@t2S{zhUTcxx%xR$nBX+!W6 z+FI6^?pK2AXwS1kt8NdjtG&p=t9L!^B^G`!Tu#C3iMES1vFhTWX4)G{@Ut^*w^B9nq_&5J-{L%_y<-X9+w0Dj+5t;` z_#I2D``$mV@clax+(x})gTv1Rw^PFRuakC2^|?5xvvyqRmEbPgXQVv8!SM6HuG%@) zRrrpqtM&z}P->Rws(r;;6o9(O!f%bbYTqgKbH-~wuxpMdRY5uJ0p0JR?nw^E;v<=Y$SzAg*g$&VxS%qd53mK|~vHCblg$&ao zSb?%)$Z*ZWYA&jTjL?d(j*1!~Beh~IQEaO-Nh`?;Xt2#bN-NEp4&#m1%6W5@KNVxN zimYqn>V%BdVpwm$IXzCR%3AWoR_8daI_m>yH(sm7>Oa0t$ONqpt4iD#&WT!m){fa( zB3X-L#hIukBIqt_@~=zt|2M%9=huOU%$lurlY{K}n>G{`fuZOl=J3BH`Pnnc8^H;kQOJ zwPaGN-_>TQ$z1bhlU5-!wP_^yPG?BGNY!St#tw0TW^ql&kPacUwArkpL*hYmSPkdL zi!^OMtHpd5Xd&r>|IaXby0(P1XWj|Wa@MY@m|Mwe4L|cv*Pdl%!?}{KJ;$02->}Zs z*0IjO3eM49VC{xAo1?wNY6X4H(KfL@EQorAwI%*b&{kIYXU2eDXC<`7n%S&t)loSt zzdEShtWAUCL2t9p42Dmi+Fq7(>LoE(dyloGb`~g)6;TUykd#Jupt;%+*0hMlL36ba zNY*EYdD@38{KPO{JI?yGKw`)O?If#!Ut-8Y?GsX-oU(X8$Rh2um7^!|McNrsDqT?) zY3E3}@OP+(Le0;)CVmIMM7uyr6Y#ex#4_zGtEQM#+AfxB-*8R*t}9dfmXs&Qq>Ks4 z)Gl+ot3g-A3hjzgosgBlV$Mgc0sN&uYz>eNw`<7)lAkt_{Msz=Fch?dsVE{ z;MaJlUDW)u;(5)<`k+cv@q!k_N`bq~i&`-2>7}>C1})U9#V5o|S~%N#BQLYjH}K z3TA69EYa`6?bKSa8pCgZ?bO<^mez_FyR`PKUA0`Gj;uu!HizVBT}T)F_rp~xN9)GI zD?^UforPD194(QBSB4y|4-2mhIa+@fUKw(*H-!lOJ-dx3>V`TN=i79QmXwT&!1$`5Iqyn>_ru=WZIkMhIX z78V}mN43|yIcRrG+s?wH{6j69g-7y-S`G`3ht$9=3FW#OIcW9>s0-nl;3j_iZr4A3etW{R37WlnZm6X>2f5LG^i?wnzmmjsdB7bw&zw506|R-r=OKwq*7!*5nSZu^FH-jf*mxa|__il;y5GOH}qEM>dG z`VQ8ml7yeO-b-rVJ*n@##T%c+u zWu;}Q@SC?@IWDxH6k1j3xArr9RH%JMXf>6q)_$Rn4vxU=q#E3qTAmN)0vRN_q^)sEj6`h?0o8Gpb>rK7S$ZI$Z?KdH}G|DrA* z;p)~=HF0(G^=+$8fpt~xcB>CU^K~=kgs7)-qHzL!1(>d?O`X z`Nm#3@N;+*CH$uNeBmd>eBmd)eBmcPB?o@C&li4v_fKcjb7!q4bEl<+fpPbK_}o~VSMwRy;yG zQM~A$@KJ?n zH$n%g+)Ev9`{-zgKYX+^)C?P}Y90=?=gWAip<4{`=8W$Lg@om+B>Y4yU$MO-eR8qA zAM;U6uM=XZ>g9*W-T88yfhTH}b6kTb>U{kK>oUyS&hc8Qc#*F*WlD!B8QC3ghx)35 zPwwqfE-~EO3!NP!lsK@&XtZ#qD+01fy3|h}G<7`e6=3HWe&8?JepJ*$h)sGLhowY68uwokKlQ*w(Lw%$JNX4nR+9DEmK8>N(OpQToC_=J{W z=}JQ*<3+wEN4k9E54qW@W+deDg?EGumBTy29IxO$-9Bud65bycDCI?V3tOm!cZ)?z zc(+(=OIEY)6}H4S!;;@mv*N`v+bkA7>o22r-sdx~@cC?DSSIK2`D|p^N+o!#wXIXiwy(2gDY?aZ+cuwe>uotI2fssL+pCmq-(Y*6WPK*t zX!}s*++w5c6v-NWqwNb)9{eWl39-rcl~2u0w(osvZnE7_IrvGv?RTYY`ztnEc|7K= zBWsJTAjukGi!DUu;AiDFk5ab%HCqX#DPh}f`#|Yr*jKhsl+K2IV>_?(RoJ(- zi%Q>zUAA3Sx)Jt+?WWS5upe#rNO}JFx#PM`R-mKKFDWw%{!6hsDUUu)T(=dlM4uS0 z+X7hliQ$ILVYQ>rn>TD>Bx_x6*b1whOZ;McTq)arla2y>x)>gpC2rX&s+=1XtKDJutm6Y{&@JGR!WBX!}os%`DOxtIX=U0X*|Cj8_s z5Y)xWiPk+m?mukZNEc=6o>zs?yK~K#QsGy7^+eW~l;Uoi-iKuUj;^8iXW_b-`XH`( zrew6+)Q7TqH!JQgppRhPXi(hkua9CSL9U=amgV2DxZ9ym@aAB=Kt08h-?(mpZkIlV zwQ*%}cZfcnm7HF~9j2!$)pxt~bXHFoAzYusx(1_1>hoE{)0?|J`XbhL=(CW%)SH8L zMf6OT2{S9IuOeNL_!IZy`f3*b#J#xw91DNqUP50-N)wG7ZQUjH7f9C6-%IK*Svfd* z?4qQ;NlA*w^;azUb*dZ}R!ZN>>QXvOl+s@(S?_x(J)3hq;M;>zdJgMm3~DziQ%rVr zc9+uMwsP=J_jZ@j_mQl3x~!hdHOHiMc9+u+kgWH%f_{jF?`=i>DA&aIwxa$at9P@` z?r8l4t0nXjqkqCmf?O5-G%FEu)%3I89H_efIcsXhAa_muOG|#EVb-cOmQ4LZA9 z>tU?n>4)5H^$6B>*uQqV$D4z89rPkBvteg zmsP;?HK+mW2XPtH$Xiof12tu>7dJsqvNmPj0kvec@Mz&Z^){?wwfsQsN!FRuQ}0B| z6#a*FhIU=8ns6R9t*OXz-@WJ|M)|ixH;Y0OtBu1{p)nKMG4#5M8E z8KF;Q^=?)ye55{ub)!MC@KO3KRubgK=(Ab=4U2`3)912kx}4z?^aZTUna=QJeKBkC z3TOBveHkkWW;R7%!J3*;F?^c-j3v05I>V>yYgnUUC1&dDSUIo~v-B5O3tKqD)Ag5F z8&?(!&(Jrq_Cw9N`YWvD^y=aB^{qV&YsAns+316h=D0K~AtnXIp6~07& zTWN6kQhlG&=c)bAy!XV!4>*Z)-_n&Rr-gl;pq#)pVd#Ww!EE-WXF0<+>sLwE`S*(c6ARD3SM(b!JpW$Re<7ubqRm!^Z_#hD@ci4N|IWhmZ;O79 zh3DTET}IQhjVKJ~-xghG;rX{kFTld{Z;Kwl!t-y7?qK2hw?z*kS?AvtJ%ohkpA&L! zt0p}KZPSY=>F#ZMDW&z{uj$cBmF%zU)h+p5>KowRuGb=2=k0dA4(Dz**%ZEAug^Nz zbW8XSy&>yJ-Oubh^~NkuJybJNreD9f9pO9m7M!~g_9mzm>w`vnL2X&5;djq>>g`!K z;R$J%-ieec@J!vMceMoffV}V={b{9R;cw_Ytac*KJQeehV6HiB|rA zo}zRu{D3}F>1O!*`dmw})_21X>I+ELS|8LGbM9snE#jcQjCHVSfrvwTCJWd4h`x%2 zYkfptO~SQyL>$rAat_z}h`ye6Gv+R6gH@B(^N60s?UK_&B97`WD;0|PK;L4ugY|qo z;+Xy#3)l06zMX~Zc~Z|NS?hUH-(`u`^Ar6|7Ov+f`dchq&rkKYNofL)>r?tZR!Z6E zh*SD|mS8<=M4Z+0ll6612tzYJvV^UHhe$%gz ztUJ&h{Td7JKzH>UToaG$yZTL5?`EkH_w?JW8x2w;gmH(J1Ub$4gXP~aH9|MEO7u)5 zl3+a3Ff75HBq_qr@MCRUnHmvb6l5i*FN&}mPNh{54#UOj2_ra-P}VgVJ;(@W4NqSm z5o|=UwnLvGMqzIb+JzZKStiUZ+$h0n+aW0;(kNvKuDdTsc#N{F=vhe-g^UU$>$+RS zsKmnKrHE0Pg~!WdMpcq^yc9L6ldS7tQKOcXgX87(h@wUvr9Ba)jrvM?5#^0IrK1rQ zj3!D_R5Y3^H5AdtQXBWH zElTwxyBe=4HIIxpcCdQFth*VzSl3{W5{x%l!_(VD_AvG+b&c$4>{aR&nP|MHG&r)C zk*72|vbS+iX;Ne#bE5GpDNR)LY>P}beq-SiQnGQEg`ZcF4H08K1>qA?vSDN4 z6H>BavhWEh+3;uK6H>AP|4AhHlP2&9DcJ~Q;S*A_5zN9nNwN_}vaSrtMg$3-AWE-+ znR%?5aGf|BG07-Gvd-ekMlmY~pHQ|%PBuz%yVK?lP-!a%XWZV%sYW@g9ep=5&8WyV zW!R3$=|&7|Ov-`CnMPHTb&kz4sW z#Ykr@fK}RJ%we_dup@GtF`pIRu1eJF#v)5_=G2bbZY*U*&)N~W!^k9A=fh586${UY zoyM~)JRf!$Ye?2-gdAfX3(tTY;{_IeV#qOGV&NH(V{G!~;0(wyUSZ)GkYj9R;Te!) zyw1WiAjimN;Te!)Lb>d z3sEOogUX^lW#QB4UgI-Tn%}8H@sK;mxgFgw_XTTTw}z1Wl2sFaqPfrbhSeN?(!0<2 zmXzkFFAi|OYh32sUa0x5afS5})O^?Y(NcrDX1A#KjO(m%WxGYaZ~Q{arQcyaYW!;D zM3gx&>I369R$|#0$1&p$*Yt~p-&-?ER>tc~o|sV=Rf-j7j)?lusKA;RQ%;^RDzWy} z8y|JTsKUZ0dTg?*7cEt&|>h#;B*XAnL5qP{}2} zH5!wwtJEc@k(^XNMQADwmIsm(UWzf!RDxIMsHRUY8VF}LZ&!YUyc_iyB_BR)@@GSN>7qjpz4ltLJ(nOQx0q%lkCJR6R z6*O0|@Qf>Ht|nP$TtRcKm4kQsLR3L>J;{3i?B)h52k+m-D7%?O!p|0$K`*n$IW9*z z%`L3miI<~-%-5`T@J`>13O09;tY^Lua~Ic?VV9#q%{N(NQtn2%%{?UReUC8rvhaP6 zG~eTz_`XM)d92>e?nXtK2U#~7+>I(^9$_Uxu84Vz<=^mbR8jLdtETI6RB`iTR_4sh zQ6xXN0llq!0jF#k}h=BaIJ z@Sk6_zIm?esbd;SO+9r@KczMv_`e=d>guU)I$1qo%^H|4)-_nqI5U(rJiV8vu^Fy3 z*we&}Vr_>#YHAkt=Af76W>J<2E8oH_!CDGy-O?<@S^#U^+APbO1gqQDtiWp9;c`?v zvl1)5oxi7pS;Z2Z9Z8;!W-Kdu*5#;9W=)cHu5>YLv+!K$V%BBhxzg3FPqOZK@n#$g z?|AWM6Bgd_;?3qPd;*L&pYrD5ju&sXX5k$#-fYLhJ6^omk%f1>c(V%&&%b!H8_7EV z;?3?P{8sF8RJ@sJ)r7NAil@y!BLC68dD|6-q&lqzR zYw?N+o^j@CRuar?g1MG8HDiS**<5c4&c+Fz6mtV>G_1sAGmDi2D>2o4nYFOR1kZGH z3v1)bxt^KkYpnfHbC$V-m7KoLlWy)(+88<8d{b$YC&S#M^txw`xmW28&s_68rFT8^ z%si#Tp84iMrIVfo<`Gs;Sfz#LG1fI$!Nulr*6{Rmo~7o;N*6uL%u`A~dX}4KSleNb zGR^be9Q3);yudPH<)1OXW-W!aUTuEMS^#VPoOziw308NVd4<)s!vxRs<~3G)yA_@n z%o~>AY`p1t(Y(ouo;AU<8 zJR3Ke{wzEjH<|FClcjd}G`h(QWZ~Jk$qZ)U*|^CJW8vAj$&6s(*|^E{kgT(DlUam> zXX6CVCbO7T6VAql;$^cW$vPWfF-u!HI2%8+zhai-cBjp|o>$C@tZ|OJo-Jk!Yj@&Z z&o;BF)eg=^|3a^u)k)UbxZSM9HD%ac&knN=YfMT|p`B)Zl65xbm~kvT8{aUSa7{cL z-!PlAdN&Iy^rra~>qdj1LT{O^SxJz4+ib`3Zx~c)ui24R({|+Ve#=D-wW`EXbSc#+NAXW~n#4&RyYhjDKo{!8C ztc@#!3Y{=VvGzmFkIk{H=4#e< z*rSW)T5k?UxMZ$pnXvMg%?+%ju+~4AS*!)H)>qA!S(9LOubEp|Z9Clc{A9kyif>n_ z&<%5kB{&;X3;k^FVnxro>-oielVqKZznXhkcsBlOzQe+^@s_!dWSxz-&0H3qjknDM z|BJo*j<2F<8^%8;ZD;Et5PEv=v;Y!9mo6QFP^2R*6p=2{LzCWnhe(&If`}TUpmgad z1Qit&K@bEf?_4w2nX@6r8@ccM`91IN^X8BJ?009j@9fTAvuA>W(sOI(pcG? z@9$6^i23*%iih$Db2Il-&^tI5@l0Sd{9s}siI;|D4SFUPy-{<@MM)t{xANPX%9k5=kSc?85L4W;yeSfz=S zUqGDF9JPb(U%b-NmB!YdsI*4;up?MfX@{D|j$mn}1FCVeDgH@HXH;sF;sNE9ZbGaa zg$I;ZdY}@=Pw{_2>CGj|QL@q(1?4DN>5qbPR8bkgl}>6^Ia4G>8H9qEV~R2qRh9LY zm!iCZ`jnhEQk0P>h)1RQiVtr#e7nIZ_ri&ttmDH*MwUkR@K3-C5 zD_1b5qhL}%9p!t}>%(gY)Kh-s5+(H|d4!rdKPjMvLduH!M1QvSR*I((E2&8VtrZ{C^m<7FZ50)@ zenIVkR}|JcKHOhe>v6My4vJH%Z9qpQzf{+NPD(+k-T|GJBB=Ik%epAVQ8(FEcT)mU zeI^VH=&poFy&2F$3747>&{K($ni0@TiIrLy&|686S{0C{l$6>S&_^kQ+QIgruTsvH z#Je7X@i1NHBxy61*K}F($STZ zm8y|S7ZjALk;H>B8Cn*pSjDC|glbHdiX!xzfpkL0X}e$}ZGKu6Mb_ zcNZ&_y{JyLqXJhc`%$;6Mg^`>K0@_pY3r0slv*t+FhlvwmBzMZgK|iSl~g@&lX4if zenC{=7UdXf*n~2H+mw@1DS_`Or=@BJZdcApH4NOLT$E}VxKp_#)gf?~az&~~;BMu6 zsn-JcC_hRK4}4d-E;TOjJ>`bf)WG+ZTT=4^_bPW#?b+V$Q|_T|vLmryd4TFOVQJt2 zKJ+rN(#Qcm1^`mp&vQ9MyT>?nPz_;865_nD%ipu~Nquzz~Q{<0lV;yzbQE>YqR zD)~@Q;tnbWP;Z8=2|TD2LP7aEs1!v(`8%liqu@)}gGvwzO5;H#)HNR~jR%zo6qLq; zN;C>e<3S}31y8(#N+OpijR%!dB8@-e4k{I-e91wjn$#}ikWyEw5cyJR!X>`j{!&Sm zX};u$(ot%caa8Fcl|+s!{iQYpo>YcPy%Ts^8O_EYpzNPHq62HFqP5C5;j_1&&9Qq}P{>&k@JX}kzWfsn%h#V@DL)CJq zQ4Y1sp0bS(A*qaokQ>B(1$s6IEOCe&`&u8`|A32$#04f{1W7gz&lbs3!e$IKN6?o%QJhl02NGIXh?1mOhX*Z&vXUIcgZiUt z%!qY((jZjJ84lt}Lr{H&JPP!p;V3mQm3Yx8RA`_tQw(Zk`3&Ms<59EA8%&9)_@3;m ze_9Ha($hhFXc^QK>KUZavM68GGlOskTn1*x=>RG)kr zts*rupH8bu`34!ZhSX7Ci`GPS@GctUq;;f1gYwb(Qi(zNX+x>+Oi zL4{~bsh5L_(AH9&f{N32QfWZ}w1d>3pg`JLh~JljX)meDMS|%7sh_P-I$Y{zKsX&M zl|&-x6d`(<{YE;PPD9;gzmblnGf?lc|N0X{XQPf*agZ1~7X`nqj-?Aw@Z0KGx(M|e zn=g(oMU7+g#nI(l;+J3XbUmistvMzro^B9gHHb+;33Rj6te`}?O=?k4NxDO7RZwZV zTWUj45`7N^y}gyAdr=;5Y!50&_oK$Oe=n#!J%CCs`*BbO`U$Gc)Pq6E^i$N(GRK2b z=w~SCwXG68$R+lnGCj_fMW6I#{aDklgvc@LY*1x-2DQ5LH%#YIU$y#<>1&i{mupOy zQ9ty$$@DGCr{7(stElTe9y0xe+SAA*xHA2jE8B6Qz%WvU{>mlpidE?!QhIPz>Zsr< z@A-qPQH?8$9qVGjHK>7FIX^787In&;iKG@Sf@ymig$389#bp}nVVj0w+P%3kEG-h1 ze_l**JsM-n*?^X^VXfTWuy(g# z?QLlT+cMkJm!*73d)iK_bZ`gSRVq2S6HSw<8Qhf)6r#;jng#cuL%6ai{OY?09gc!u zefOXvQ1Gkoo^%une)ZjxjzPh%zI)N}DEQTPFFJuMomOp?8r+*sMs;hI9oU<`#g$3N zvg;*{PDjmY)jl|l&P0`N(Ji3c#|gBGj^9z^#^tz-HSRkG8H;34#5sdY@B zN^J`sMn9L@7d(P~fojR-dy^iKTE}#pD~rHy<44hxB8|PhWCo9-r@1o83ReC`(Q}w~ zy~iPzb`jH{m$6aw8%#46bT2lVW}|{S9Sa^qzeCmNbS`)-{Q>8Dz2lYOar7E0(ED2O zc=`)h7J=X5PoOtZW4#{)PoTHC(n;A)J|Pq7T`7aZWa^O& zB`2Mf_f83Ui+Xcq5%@*_R7z30cfF9QRL7icJAE2BjasOB-Yr6=QD3Q!Onx{Y^aL=S z7Q(bQr-O=cWjijjU-3?-#YGw~#nWk+RNs*4G>$8amTEF6WCl${)ok(xQ%Te+_8*95 z(lV$$>^~6Aq-D9%>HJ<}LuSzzQ0sg3WlDC<$NK4>O)H_cvwpf~(<-O}bJ?${X?0ZC zTwkUaQN!5!=F-}zX>5ISXNa<~1Yka@H|*F4f;)Vz>Iv;kK->FCT1UQ8QHEe%;r zo1s?c%M4yZTSzSpSwd5}GRctOt=3Z7R;nFYM%$xCblGYxr=3vm6cS|4X+LTit0!-zA8}>T znhjIQR+@=|J}tJ=&oJjyHG`!cLakN}rY}*)yjkDv^eAe2p@$*c=yB9?rg!K`u1pfr z+%t4LJuTA6uI6tA@1Wxw$`U3yij zROnv%BWlO+@}VElYp6~&Dl+}dmBnk@`{@m?bXM=l4Bk&~ab=Rj=GmbA^bQK{k^AXg z%=u#T>Y*RfKe)0;R`a@{2j~M-vS$tBBl<{cdH#$S^fMZPdUNtHrYO|tpj7fXjYZ96|DEr18jsqRoIwuK5~wed4W?44dm*Xh5KTfE zq3oCWv>ZxrGCK4NS^*WLu2@ zz!6#p)#)tr}QQ8OvHtStKvYmA)?XeSjJmae^?OH$q3A+`=?$(d zdW`kGc#e)lL0=!|=ol3A^>Ln#Lp2|_IP@Z&z?DvCu{+U4IvMpgs}EkJZ=t%dyT;da zI_h=ycKtP-iF%QxeM9GW(k#gO6@S1$W3G-_h-;7djYB zJ5gQ(mMf0gb-4Pfv6SLuG#b=F_y5A-9{pN$QsPf%0Krjj3N z7HUmdU#8DdHDAdfKhZBx-Cr@74x`qx-?(3+$502@o#+}pfhx-G*VpMOR0;NfbFb4g zsFsdY@-sb;>g4ccx`-;~mqC7^mr!wj22(ay7X5zE;?NuPJ4`FXmU4ssfU3!sa)bUP zauRq?{gqxv)tQA1eYOde_jt}N=$ zu6a+jF{&iH<~`M>T_S3@=RRn(W0?}b`wPgH5v+eUsh4RxRg4a=|g zLm7I$Fh6xDs$%&LFM>KIImVe=JL$8m|cMp5-G zu5tX$w5U3rOY|IHRGo!_-sOs_b5YQ9d{K1)3VO3EsxC%B&vQl9Wl~+OV(Lm1^mJET zU4weWmRVd~FT`sX#nrb_by**E#nnwH=%dbG-HL)f>H^g5DCnauRNaMwKI+2McTvzQ zU9`Fv1-;V6sQZN+!4qP_V%3i@4f?2yQ!`P}M_s)784CKWN>C4>pvSrd^)TwPSIMwM z^%$ylsVZS5)srab&90Ps8U?-Cl~&K8pf|fR>O~avW|yR1LP2kKWz{Pv=*_O2`aKGI zvn#Luh=LyHUr?{R(pYbH71SFj=y5(-y@i5)1S_g{gdE%F*9xns-a{qSZV;BDK0v)) zvUyk~^$}|Cpf+KZRrasd*%me ztA?N!vwg3phNEh;p8V>oQK$+vwuZf=#tM-?YwQkdpeCT8Kfs1+Nz|}TAA~hh%iw&& zYG;NuR?A@;^cC1dt$>2Q0-LHSm@}=@7h%oRDqQ2qqO=oX&DH9d6Z#Q+S*?k>?R7S+ zg<1y%{W-Q$>!SvEe;?LLZHR*29aGgNsMB8Gho!2`xw0L>tnbCvYD+Hh=GI1SFVqSm zW^L40r4EI*QTs~W3Tvwl7NX4uWRUjiFw}DPv}mu6Kt&gR5Y}EDi7Ly~K^-kbCd@q) z+EE?LHLt2M)e+uFO_%Zs@2pNjZSCL)@2b8fAv$T#cCvA4SJ>N-?X8t83QFIMC1u5Lm#iiS08A}8PXH1#YB-k{Ue3#d7x{KM1KZ%}Yt($s7e9EmjbI}{v=H1!7* z9Emjb8dnyDBax>5f@yFh($t$GjrV+;3@oqg3uI3H|FUzJoAbqzQx zeN|5stf8;!!zGR`%gO#+ZCNfsTUKaze@ufu>SDtONI_fHU{w{%WHpu-!iT87xQ6-d zYlaV3{p9-UGZjYphBaX-Cg)?l7^NuRQvD|YH6wN;iJ@Kso~+1)#_3+!{@8@ zqQ~uJev{tWx`+c6d9;DzzW#c6zL1 zwK@RxINd>3s{^^RDD=h@Eh>8>If9{Ww}-ziGp8*uT#gMpfAgH z>Nu_}3Vm6wS0|vLFU$4nBowqCWvFkVp#3OAore03y(7G>&P0(H45ryA=(l%+Iu8Z? z_HIxYaHZ3q!d8WER2QS}g=H`;MU5_Xl5A2}pr)}teK)DAP?K0Y`*@zX~df=lS|a=cBr3W&PmCsEaxFE zQEqprCqx?m&)7TEQz&@9-JzaEL9d=W)C(x+4}ORG4Ocqr32tln4mBHfu-5MIo$9wT zZGZS~^{Pz!G<=WxBUcuM{y*PSuZuL+?sPc(J@tl2W4b}!S8vI*)8Tv7J5ra!KTz*U zT@OE?K9IT>o~b_K$|6?^JqgcJpJ3XRLOv0nsg5fAzC>OxbuavL)r%{OzjGZ@eK5`A z4J+c1s$v@aukSBZLu#q`vSBpwT zM4V9lalYiT@ewE0Ae=9`><#jj8Y;ETIHg8l&N5SXho4rXFs;ngi{z{tgK0y{l!-X6 z#$npfGPTGBH30?flo!w-DcCbP;v2P$RP~6p?GG~~X z!MAcO()mU&-oZd>L9wF6fs^`1cu4guJT<~g3f4}wo_r~yjH%jdxJ+o(Q?-Fyq8(4whHzz3 z=(ktZh6@qsw^!9hh@AZQzN$77)1Vh$O&iUXPG(eQ|L0B{i|SF@m+0DfF0pn)o60qh zJ}$60!q8@LWs&W#)i4ZgwwRB<_Z!+`sg*3}Y9Si(W-4)N>re@A`Z8spf>}H(pSBSd z&*EA6w9TkY&s5^8Z9^UR^kv#E#MhT!dtb_zQBXU=e6gMzl!qS|>Bw6zx1E~22VwU~AZ1#PXxv}`VDYuy`BT>B2yt<^_NSGmMF^4ESs zL0hZ8b{z$6tpVB%6tuMlXtz+%)*7JQ<`QkKf!bXZw6z9me{iMK_)(un1ZjVw)-^lA z^cZ!x*;h=YDqMG>%`{l^L_wQru;wkq+bKgdg)5!4Q(lM&(KIg6P8p(^n0CEKHcQKg zX%K@C(ek69^)XZ{$R*kv!?YqeU)fGSM1*O@rG8-w#GKGl7_Nn&pv5m-3&Why;uo$( zaAi9lbSzphT#J?pVv0jSYhZ+yDCXl=NQ72S>i38Ut+Ehn)q5BbsZ~R*@AW%V4KC3F z7p2wYf)+TB$T+RG$jMsZE=0s@^`z9uc&!0yb-oJ`30h+*H8MeK#wA+d615gm?MMkN z6$LGDCAGFV-&*TJL@BMklp0w|>%=8m*-C3&F>P7be350e?p&D!+T6-&JuxS=xs}t> zFy|JQv%J<%h#!{<+7KyUQb8Lf=HqQ($=X;Hw1FjS<5AECR#BUXf_AQo+7uK--79L- zxYFsmPN12X2CY{WwK*tgy{f3q$DGp(6^X2!<^85R88B?CEAaw zYdbM*ZIS568rmLAgVv;)+WS(=^VifqkZK%SOFMvq)}%Vx$6WJB?;7Pp>u8x=>11y- zq-Al5dR86nph)BAsE&4Aiv8b5?VJ#WV_jFfh=LZ5y4p9WZmd>WPs>IPV71D6+P7S+ zR>|5J>T6d~(8lnR_9F_~7#eEValY8sVjT^&8>p1m9HgOk69w`4M%rx@#OE7nzoX#1 zH`e|@?daso^ngp$keX-@Q4p1GqCMdfQR$|dqZ(mSntr6b#DB~V>hxoxYJM$ODuInggVLQ zYp0b*5ti0YtH33q%dcoDD2OhT748mmpf_=xFCXjA)=Gk7&Y4}9ob21idv^ti0rI2N9|(jqP0L>O|BZ*RcnR1 z%hXL{-HounOaf8jSG9I1h!XeGI*6Pkp?dAezFKFgMv<>+-7qIaf?wCVqaYGIQ0vJh zuH->l8keX+4AKU2iD>U2Z3qgYy@RyjD2VnB(%wWtw0Dp;8U@kbLE1Q}uGU~}0t%wN zL$t{#i1rTArV8Es2k z7Lnt%m6!&x-*jya3Sz$#wDnw>WMap5krTBImFmD2PDL*S-+v>ROW$oPI;A{S`4P_z4`MK09taEWVaq4rSBMn|`t(2IL&KWf}a+#JS(s;yd znO4p=-wLg=NaJ6FuF$HX;A_wo+KVXo8gzwL8wFp3uF&eC;A_woS_2e(|G7eIjDqh! zS7^<+#CERK+Hj@w?Odt7f`aW_sdYrbd044+K|zFWrS>Y9IMypQI47mX5?Bacn5l0>nWDWpN1Q>*QAz5ZqSBFt&iNKjgi_GxmBAi^-1J=+AOKlk)LRb zq<8*@Tb?6CG83Zi0%wY^*-Dt1KMkAkS!5$ym9qGCt2Pf!pQJF0!kC8A=- zw9iox6+5OKLP1pQxONx?QL*FNQ4~bQPG~1k5EVP2eT9Ok*h%dS3Zh~swR0$lQhlXe zbj`=2R9|V|2=R#0DeW>B`-Ug15ILn?;S$e>Q`+~K6Cz5dv>&;|Rd-6eDbjdE>6CUG z1reoF+FcYxlul{)Q4mo&r9I?=h|({Sr?e-igSGBNp4J>S#GT=8&4-a^H80e`TAoqo zG#@SzQM#b1B8|n6^r#D(A<}q6>7wS8X?{^(Yx$)Dqb_L$rDCG4Xho#TMqSm4bBT!3 zk6HkxT`5#4>L)D-^?IqYQP;Fk%n7adKWpKb=J7_&sGqecOoNEhFIueBQsah}fP#q9 zuUZM5Z(RGAqHbxWFb(cRx3wfL5mCCWm6wW$xT7WGe92{Bj{04zg!4f}>8@5)YMXIS ztARPoOuZBNhgK8QAfog@tBq+x%e0MpsMWZ2f{^jK>k#eOrQHR2KxC89Tx zsvhB?H{%k|4lli}lpgG*ca_Q??5+0^;%^~}-X8_EQAHoXl||sYbgB=M^Cc3hkF?FF z>SJv4sropa558H~^a*ml4iTC@8*|PuFGN_n{a)u1-0M0=<-;_%*Y%3ZF9r9yLi#-0 zG7IagxJ0z6xV{zz(Wc`1dfWQ^^$n;cX6Z=(9BU7dYv@~eXjG6?&%&dlLZo2r5&9;v z6n>|T)OT`;(io}l!!?u;z*R%DGDMy zrF9Jj5uP%-iGm1E89g5gB0OdE{9Gc!lcX0!L4+qsFU$oIo~==3^y3|Bh2-s9t_@_Ia`!FzFeJrM;lofq^{ zTq34ZK~KW@%69rZs)Al#>IhRZ=7g9|vR(-VF`Z<+3g(2EPO@H&OFR*h^%q4NKkv!< zOH!w!lJ(|7EN=64R7JfdYJIQMOsQNVZj++7;exo$w^3E~b|NQ>+gyvPrgxCK$UuY+n@l~pMBJu^-dn02c~S3+g1Ajh{WY9#t#vJ`mOfDGCesiu5x1$W5684+ zUGGKJ(ck0}ahrPjD9j0QoBH}#%(;c-d`V9i;>V?-K26G(G}Pyb`FPx>k-iWGahpc^ zVv&8Lp>oDiZ-k`TJ4Wc+r^i3#;;xy5>V$SJ> zocFH`ficNqBy&vn(OaL`9wF@_i>3R&dd6K6hv`a=m#+8F?MuY z=$~+jC{7DK3k6qe3;lD<2~nJu`XMe6#c8E~iGsLIs(w^zdHz)WgjD0u*7_+F#BJK@ zXShV%rmcRCOI)pO^^08MdDK?_PRf_f_p=a%BiK&=74=PTU#45Avh7pJEBYN&rS`r| zcezBQroDb21(BK#`kyF>)O6Ax3-NZRPCBUxcd0A_QI$@*Cko;yopm1+#8JBF2AA0C zZn~e8GrF7ZFEu^tRXtoPiS*Fpg;*TrT2wE+1geqK8Qn`Sh3dk}QExp7H8Y8sa3K^UK0gzlzw_06vR>b>Ge<$ zN9nIOKtUX(zut%o;waamUelYRW?Rna*YxJ7by}h50eTD6E~eM@R;a7V0nr2X)~LHo zgY>psB91axZ;ygF%5c3C3SuQA^)4ugm5kE6afxebwBCbDJa0$q{kcS}WVHS|3SuRr z^}#5Jm5kPhp&(W=S|5ReSjlL8lvG!1j6N0xv68WRx)6_!jMXP{iD&UxeKMxiWwDZR z`cxFeO2+FmP!KCg*Jq<3Rx(AOhk{tiTlzv2L`P=oOSsa>(kP|CEPXkqL9Ar9z6u4= zkvaNW6huen>KQ1gx6acyq98glPv3%q=*WEi9TY@I7U(-s5FJ^l??FLyWRdW3~PW=et`oJbJZGYQa53L^;;zo+yZNtkHeA#D7^|qf;*UFY9s9 z>vRp%;2dS>CYM-WhF(zQWO0q8=nTCGm-tF3LoY7GqZ}D}fNj1FdW1;hQH~9IGzy{| z8}v97L^(F-i71G2Y|z;&D8COvlw*UQgn}r?2E9BAq8uCaWG=Ct8};g3>3lmk>NQai z*Vw4n!TI1lbtBfA`Tf&$32OJr(VJzBx@Y0)(OadUe!WAlFP6!l;XCzaQjMc`>TRT2 zMeo)-OLdHXPwyr5dh{py0I3PlhxOr7J+0&VSS}ICIH{+jAd+!XpNN7;##j0j6htz< z(x;*zl5t9(fr3cJDSZ|fYu^l?8GTxxi)s))pJ_hkgh<92eGv*G8E5n*Tq2TjR$q>S zNXA)xB?=-L=kzrwh-948*KvtR#(Dj16ht!4>l;xJ$+)0zK|v(rg1!v}k&KJ_4irQ( zF6z5b5Xtyje-{OjjIZ_gQ4q=aM*qMyAG?gc(LWU8k&H|FM_lQoHTyQ^lKu%-HvjeE zB|Qss!WD8!KgcDntV{ZFk;Wq#m-Met5XrctpFu$+tflEX(zSpmbG#0zq7yZ5di%8>D4Sf9m-$4emCN^nzR>lJQ6{A{7zw zSTBzAC71Pyd7=m6d=SYXMu^ll!(oJD&N5TiMtc~MmQ=wj7m~^uw~Se${*}B8gYr=)cYDuP!PND zGn&hsiNw!nhiMR>C}?z$X&oX88oh<+4D(u4Q3KA9D;Db#+`;@}iennYC;Vdqq~Hz~ zV)V5wGt?N)CE^p2#+xXJPedA{Z0n0M#-f&(&S+Lqx2-)|uAy(?*qB(Uo`p-t#7n{2 zOB&<(QbegLWlY6o^0#th2A6mbFJ;W;5)p|~#ylY&btq*l5IOnRFr|z|mXSjr8t-BH~h*QpP(Kz9mDh~%D?F(zZZbAl2{F03mThDCD@n=1Vay3Gw5ZVq|k=ITETb@vCHfhdC3fzZz57_(5twObz3j)EhB1jbCuS zg&wQ?>KZpOZK21+nEJ+TsrfODjJue#|ESG=O^y3p=WaLr?SH>Qmd&n2EK9gGrO zq9)hDC@tpWHHZ#IGMA{ybucQ4H1@RkET)4|6?L%Ik(iD~b(wZLrn6B~rhOgL#i-3C z>U`addMK##bu${E_ONGFH={ACA$wMJGn%1xu{VuwMhn!$S{KQyMk`bt``Vy~(FPUI z-eG$h?YOQw;OorZMhC8R_B{GNCe7%Kf^RPS8eOG+iRov&it|BCyuZ-{1<#KDMsKO5 z#%o4j6g)cy82!1Rruuu#Kw|*vjk>2}1{;I8=8=U>AIA(ahN7z1(PM`jZ*X08z*AV?0+nsa|)RG1i!fDl_#+%s68*=7c9ny73mK4J{KCJJFbiY49YO zWXwRplVq|nOUjo_G3Ib(J6`um^Lxvfk7`+Wpx-oO5tq0=ryHxJlE`#pgH&YfOk=wc z?K7lg>>Ohk*Hsn%GyNRnT@?Ih`Z>n?DEQCxbBzyB@So}D8Xt0HtIgT}x1VQx%$3fL zV7b_N#;2(2b*jcLFg{0hXxb!psquxFkJp!$8%Marb-mm;E^_kgdbx3qOI+8>jf*0U zUDs`5mm8N*2WxeTU14O)w4Sl6jPGPx|Jc>WRW5N|uQh%`!F9dX_!$M)^;+Xs6kOM9 zjo(mkU9UBMN5OTy&bWtq{9;!t!+3ytQnRP^w(*clT-O_oCtPq{4~^Yqc+`b^PdfjW zc#GjBH9B^y;lp*+0oV05gQDQN-e%}hOO1C73kBEpb|W7bT-TFgcN+OoSw(xs?luZy zPPlgW7)7||k>O2e#qKeRV;Wq^dyPP;ZN@$$ge#p)E4t12zz9c`nc69KzY&Q!;YvPW zL}S{}GAm*~HexXiuH;XQcoba8nMR_NFZt9c$(8MR$){<-ETar+RngW3KR3#8iKp*D z{_JP>YZLm#aSI~(Zb2mfkjx2@e77Ky|AkD0Nd6Z_WxfXZR`a`{FO6!bZY)~=CFaaD zpB-GWHIOIarLi*r=29U}QhjT*SV_)*=0j~TVNvehRoulgM` z>Y^I8`kARds^F;Ge#ec5sOin_Gc`f&ZuW$!85jH7j%~{cqXp_P+m;h@?a&@@QVQAw zq`aYLny*}YebS3=&<0`Qg5hNopZpih}ou4Q^dpE75RS8%?u z-s@w}7#+E?9MHqe8KVoPmF=`G_N?)$)Ro|~Mo(0E@7=NIj5Mi_nEFXw3qEfQkUA23 zQLY`@7``?JVVdrJG4^X?C>ML$v;JnjmN}vQ;Tz)(o|f(Ssz-r>-xwoN@J;DA#u%v} zrtw_jio9e@<;qf_7nw`O3>5StbIF*6f?i}U8*@?6i_B$XJ}SA*_p#Z=B2Yf#X`%(uom6!b9jo$)pbdYJjn*ocB2X1+JJ zprD7D?~QF-=`><6`=z|G166J?`=z`*)6o0O55_K@CL)5@jXfeKYeP93^t184)XmtR zjSo<(^PLU)#W)~!Gxis`Oz3^)hE46ruTs#4a?|*P&zI?d-e+zZS-6z7tjDw8jDu1) zV}CQg#GKIk%x&W+SC#{MpSfe4Kuz%|M1D8E;u=T3>KYpMyIdc9C41L6jX9yU<(_d) z5eaJZGi~J-)cppbf<>XhXSg z{D8~6Ug%!zed8z8pG*(rRzvSBe;U_$S~_b(=^gygxFO{k`p~s4-p~WfBPnP@d2HOm zoX~^ZW4TP|N#(I|N372Qy`?-h?xLWbszNk| znq@EzzL}+FITW?up_`RaP}k7SYN#_cQyr`k7`36+D-Oe~#g(N( zzYdmJmka6)JuSnGK};;tH6J#C*KYP}pq3HJ(%&&3>nEHp4V%2P$l~ zK(%Tg7+1th<;rwG4-iGoHkbx&M8(WkP|yQJakC>=wxcVnYxtX;QSbY_;s`XmqP`t| zn*^KPQQi7=afFz?P&Z1~A|YlPssgKrgqrV8Iu<(&H3y;Uv0iIJ&7r6| zy}L8Lfx0uf57S80zJ;$djX`Sp(q zB*L7-CF-V;=6oRsw4FtoOS!}oA=+FkwJRjr+{~5E+Q-fY#hBYrjhqp2G3Iuz@w8`J zd|a%#3pFOK6w@Be*@fLd42Up%9vMB&{IW{`5g+rK~6G%KtbEt3+6Q;5m_*Q z#x&@+qLTS57yH#B#2L)rxY++ztzJH^viUpaOsHNpuDbb$Olufd$NW?3v;6hU$1>;3 zarI3{eYj_3ve-q3xQ3<|7c8?+Tr*SQ$|4Y-XkluYbD_uJxK^f#Ia#zKuAP}rYEE1S zvw+OGEUuGT2nD@ubTf;hptp_gW++z{fw)F5GXm3~?~Pt&6bf1qdzmpPXhrO8#&L;w zL7JI}Y0&pZnpu)7ofM7U9G7O6!L*{$JLCG8<+!p~+7iEhW(AqEVO)PRMe4Ks1I#L1 z;+lWmtSz-a?sc<~)TeO+&6ZMn@F26jRQ}+>=Br$+bmY$nEgZ=|5|H=Ie;s(n(p^y+z4|JrZuQ>f@uiqhw#C!iog! zU3I*{^&VFylflxU6tOoq@4Bq@c#;&f9#58n*5fHs(0V*W3R;h6ntS;&;Y<5=k@I94 zv?b4%g4W{&=6+l|d}+T>ra@csA}MG~UMvOg#Y?21EqRIg5w7pD*TcA_W+qpb1NvN9 zW`2f(K37)A`JmN#r4+O}uabgR=hafs>byn@TAkNQL96pRDQIb-(Wg1+Ahos;d{6Y$@x-X^R zS~@HR*U}LwxR#De!L@Wu3a+K&QgAJukb-OJq!e5QUrE7vKP3g{{j?OE_cP`bJP%M? zJ8OEp1Z6tg0kyTWrZ);|YiCW0g4)_yQ%6Bi)I{8gZBq5=%QIhs(Ad@W<{x^zL(4z zQep9z&H7wd)t4rpBv;IaLXPn>GMJj6en~IH)Qn54{fgN}s)pl=*;$Icm7Be!b{XHB z1Eg*S{9q23Dnx#A?Sl!ud$dgAz13R>#jg4U0lG7VZk+=7<+TQUt= z>Tj7-aShN?|C>1j1ugZznX|aERUg)4$Zc~jsubJK+va@KLbjcE%tfdJY&-ABH9!mh z?^4jChLkt-esR}a!siob^RCPZZ;E%#H9Rd#g*U~!=6V#oDc&_VprGCUuDO{D+U)}) z?wZ?B2Wurq+%vb!w1|lN<}R65J>r2}AM|PQ(A>k*vQ>yfKQ!M*K^*##xet}f-b|mE zAEH{bH&bFkIfbV$w6AzbL5qr~6vUdnq#)L8*HXhy;0Z|5uwVQ z5M9=6VzF!~h#(tM5Hq%&>{`^*>pfG zHqi1!!S_pnmJb(fr$K@&ONe$^m_dRqUoNqo!B$aBgSdCF>j?5lw@Xf_R#!^95TWT%ykB&I#@4Ay$}JAKS7H5g}Hb5c~F^Y{3XC5jAJj zp9LbUQmEyl9DWg285Gn%Bdv0%*Jt^fkyZs%71qyeq?Ll28__sE(yD@5Hns&*b=2Eq z+cLd~+Eu=De3VsNi1?1{lP}7uE0yGow(1ME|*GHn&0tH_;BwDRRPQFJa ztTw16CVPXn+M!_oN?ILIuzw}3PAJ%;QdU_aK5I|}xpl+_Cb`%ubCL%}|jmZhV* zPY;`h$MlOYWA)=X#Wxa3))1~N{(W7NHO!V)&KkotkDA4fhm^C%qy7jT9AD0wh)SF} zf@umWe&JZAXXI3i?89X?=%+z7ShkKcJv5#8m4V3i?89ZT*5; z#`dp`brS_WBeu0}qo8NRcGg`K^o;n5bsq&iBeu65qWXKzjPGDQK|w!>9W9TB;=Tm^ zBzCgAQP59fXN#hspTsVfj)Hy?yIK|s`bq3&`J$k1`l{uJf?peVw+f@6rrN_QhJu=E zPb&ZgHPv2LFsga&1@XPDP}FB7m&Nz7!ci9ot%>hvMWUiRZiydgMWZH;+!;UEibcI2 zxb`04nuRuU>={Kfe3RykBJ^Gf^# z>jhL1$F=xLRx+vysa#}=m4Z4=ZpKfwDx*G}e>Z-*RTWjS_T%`OR&~_Ql0FHutrt9LXw^f#P$e>9vGo!vxOig1QmY}Vm02!fxz!lu>8PBr z(rSuIBDE4$Tg_4Lk%kFttrn;Q^I9aVw_2e(7k?$;ZL2jZy+XHyjaFM!jT(ItHe0Wt zmL&gdZM8bMa@HP{@Q&39b*9usvcu|v>c`IeF6&h;d^faua*5~k9_uwB`b(t@vd0>T zdQ!>Om?8W-Kw^pG_voFp*wAP}kviQq~)_T-g|5S3o+JMUT_hs6Inl*Y#!bjFt z)cVmgnchLY)jE}YZ0$s?Xzk0iTZrvZ%kWRE{Zb1OKDDx>)+Kyl9g*6WaMU_2bs*u4 z^^MfQg!9%_sj~^$)(xp^2|rnPr92XUw;oG56CYSUjo{t`=RGvh(`iX1BvNM~smh7I z&OoWUiGI#Vsh1OrI1`0vP4-_WgPo;N@Xi(NOhWCL%j#0j@~Cy*=Z#=zGS@s>bM~u= z!OlvUR=hH#RYk#(4|di-K@W$)&RQsVlL~g$MIGwWi!J3PRB+W;N3gRI3VIw2b~Z)% zhFxcCco_w~3I;n{q1v(dOR%#I3VH_&cD{mw{s4oW9Z}E&V6d}`5GgvnKU@2&QiBph zoIRz6Cx$xHq{bwMIr~XXNDOxlkeZel;T$A2KQYodRBAQZ8&bEedfi6xwKq;4gabk3K0kXXvONXoNB zY3EWYqeL0!3aNr6lANoh0!x&2u9J!?QO^0cRLK(Motva8lz73pRjP7{3eN3PwM!&B zcS)5lP|^9W)Jr8&oO`8G9hIE>rJ9te?EFZo9jW5Xlxk6;s`E3hd1QU5_9d!04~aB> z@2TNDAw-8(&mc9Nr%-dM8%$?Vm-}Uq7oF!(H`v?6i_VLvwd`xxn$An8oz)DcY%Wp9 ztmXU()4GhwAhn!73z2=S5B6Hl8>p;&ua>CoyeZYEL>=dEQmpSH=N;5&vk(vtVoPVGkQ(rAn-}yj@@83&KkH-97K%vCF;66_77u`>o$)oWmh z#?E+DNVDNgC4@-pI+v}+&eB3`J4csj;!MVzo5xKo(bQQ9b!#B|zSUV3Wezf!s-uPv zXJ4&4YocZiH<)UpmUPJ=&7Jj7JGvN5FQKZkH^rBojZjS&8ca=4msw1wg|j*8CX4B` zaJE3fQEKT-MZr;O>1-p!_o0=uGp4~lq&mBy%Cq)|RA&!VUCm(Xg@UJcYiA!6JhfXp z`=MZ4+BgTGU|ZTa2clqG+B%1zU|ZTchoS1TXKFj=2visLOl{{R#6dnuhhgUqFg!Mg z5D(%P1mDA_IbcdeC=4$bgyBJN7*6W%p63qCVqcCJ7gt?g=LOD=>%4ry zkNHx5o%Cd1nL5bRQ@lu7epQI+Bly+QfL|?7Psy3{r9jyJDh1$Zd>TNAHz~r#eaN2I z2~o&8Hl(DS;a;Q24>`Sf9&et<2lLp^g8h8ub!=geJc!sM*k%tRws~R`SR))C4`Scz zr>D5~MNGHv_0v;aImMFOjDY34*OIdYiRp0M9Hb<_>cr5VU+j^XGLT(kuJaCO)&t9e z7=M@5W7+=$;dcfYx>CisNVS(caSX-PB~tB2Rjd()9z>*y?G$HOOc7U?Sfg0-v&{7@ zdF;#2y?0_=VtVPmuD$jkVqENz7#Cak(=5mXLk~O`qC|h)9H##}r5KjuAj1a3a1p=L z4&wK^iXCBH;@sKGrah0CS8Pe=k+1|YMa-@;YlTOosgS zvnHkt=nB)l+5N;prVersC-M7OW7~b(J?;sGm*tPUV?tPwwer zN_Bp&Vdz0#8~{srsVQuOct*oeOczsf=6S0aEdoC%81AVcNliQ*glG(2f4uO z53rrC{S{MSe_0HP?{!{z#B#*EBENe%VrdT2r>AROIoBwr!_c)2x!0IGkA2HW_l70g z^N1<-<>Zw|+-c9{hvN+O3NNy{KRib^vSs>^ChXa&kbVW=IZ}_6CY2oL#|NI9q8{SO z^Lz39-aNk#&#&nHXrq%A+HFl5hqw*3Eo4dmZ1Q@NJ_H3ttewij%FUL{N1 zf85uD2Z3_oy2eBqff6C^cpl^pcFnuSMb4+M>c6_eeR(ZcJj+CVNeso6FYeg(>3=_- z*Y%v&bg_33D`NkjjtxCX%Cwy0o+O6fc|=Zet=g~QFZq2QrnpLhd)$+VRQna~p5n?6 zsbbuf-+ujz{4m9p-#zZi|4)~nd;4=QA@?@q&U3m59IJoli7D=8qAdS?X|mt_?D@sL zH?LIt(^llkU4HYLS3G%V@Y=%j?V~t8;)#~R-yOvMigEYQgEW~9_p$u!S?ooMvf7$A zX;m4H?LW(7&;L)xb8nTX!?@S(s?~@o;)ub}gA8T&5KrP{rN)c+#K1P^zT1c?6WBif zRjQZ{Lsv~EuO-;0yWgsE)}qB(ga4}QAbt6{6Sb_|L;DiMUB$k9F%C=1xm9BM_S)C) zsjx0l6BBC@sZ;rzQIXM*DuxQL103Y_3j1{k(>;lp-qjECi#mgSd&GKkZ;!|$&WP9x z`+nK4fBVw@{k^mAmwk=7*J9s7am~2bF5Z7#M_3#adu`c14iN)a+~DKxImbQ8F@Chg zl3}l1S496k zDfYK)c(ZoBHJ9>-+R?+}P&+!wh7MxS4>`T~`?WWLoIX6Kf;sK`CC0@yZ=as~T78kd zn|P2e{0#-h9XZCu6#EkFb><3TkUw{cu;;grPYQRr zHWS=;<92M^bvL%>Y4R`gxYpvH>z_;!_hkFL;+`y~*!MTD@!!&5A4TfyYA}8!&^;xu zx$M*bzAV_w=HKW1`&9cHb6+{vSi}i%zilK>dzv(c=z6AT7 zTttBFsiMv=;yGh@?Hc0JBF^bS#1v5j6gl1Fo;gy*Tq0FOw(ax6)7F)L26=i5bMK>l zo9(p)am7|)PaF@@Z4oTTem&c#+s8#75zVkq|4)uP2rNwuUEB8b^8Y^7HJAO}C$GKx z`|1CgJ$<&V{p)?SAB}%H?m7;Cz2v-7?bCCw(UmH$H2V>@uSFbH`;@%K^E&?a{36eP z=3Kb8-@g2($Di+f<+bG8$MD&w{QWZXN`02;IrmYVP5W`k>&(Ktp6gyA=IYF96s)a~ z4PEsX`}wk;Uy%ov;7L6BJL3?3=NEbG_tHr$CgzH;uYZptlhQnUp z8wOi@o7d0bzlnO1YWxoN^b{|W&SQNoN>|v#_f)yb zM}B7qI3r^GNNd-4&b8RD4SUYq*Pi{X<+W`h&;ORQV?Q$X@x0DmUeoRK{?l>S8L=NR z`!U~J3Cc)ub}#ZIXL(HN=_y{k<-(gxPjZ(&`?-Moya#{2coKMCc=4|hSj#()+Wmd1 zh^H-{2uof((UT3I&hL71IqSIBo;#0yd*Hv*J4kCU*s6hS=t-7(!&a?g?-Abo+X)|1 zwJh9cASWfSu{(*%-`q7an2qb?AiuYW`(o}A3ggTbDx*Irr77QkN?yB_IdLf&%KZTy!_hly}3)Y zJ=I?J?c*ZP|CYMYKRwQQ<+o4I>-ay*^nZ0ma>wOzPs!^n{S-;d|D zglC!lug*xM2{pP|Z$gc(A*e@T|_QQD2eSbRDHJ824nY-+WmeU2SW-i)Z zT`jO81}>uOog*OCJ?=>^k9SX5Qvj}n^{+wQ{tebj>rEiPPmVmDd7l5?cU<<8F7CAU z$k_9>8I|Pi{xI|)hxpY#q&e*M5dQ4}48`=E*PDGya*vC1A-*IOZTg~Z%gNu-M5=q} zL3Z)h7W0AY$BL-xxc{0``9Anl8r0^xXR* zrik{DSueo6=V!ybKeM50+`ddPJ@+zmf5QOF%o!sUYY}g<_rqcNVjPAZq%nJ=6z7Gt z?ea4v+D63}znl4+^|@Mbm7eFN#y%y1w?Nsa{I~P0m;qZ0Lk}XZG50uo_vhEx(^I_2 z$rP9?ue0!c)8W?&9%K|R%YQxYNyL#9LwlZ_5d+vZ5j}9{cU`^W3Up6rzjGl*u)8Ar!nP~yMWpV*t`qUA2m89j*CX(x&iyS)-d`cQze0JIJh_)_pW-Ul z?q%9j|7tw<*4n>>dG_V})11$~7JJSyJbvz8mur9RcQBDE&NU3#Z$nsl^d!C5HJ09e^MJ{RS4sl=bvF2uY# zG1=YHAg_23Vv=Bf_shLBsAIUc-(EWYza1B6&|bHJEzf&9#eVtOjz5g&JpS$}Ui^sV zT$;FU#ZW9QuOnc;mh9tVo5gn8=M_`z`(hur=d>@up2xmDkt!SqG1v25z2bLOP?~by zQU9|`v+vjQEg7HS{OP|h1orwH&%e7rh&4V-jnTes&ps};=jpncs}>}d^Y7HML>)}j ztYGM>@!D%yP}g!z&#T5FYEWV*wkmgB=w*H+q5kh6x$8x_m+Y<^K^7@6L|JKV)^d;_T{^N z8J$8Z z#&aGq_muyepJln@65=?BScDkQtK>f4)tJ}P?8pE4mOPoiw~9OM|Ku~s9s&5@@bnQ! zQapXcF%eU8KZBm{x#NBk<$O#1-}!v8UsvKy$9^>2Z${!>FYo7wJLj|H`Kvca_Y(e9 zs@THZ`R#9ZB2_#ua*zLKpB>_9C7vBHp7T!F-S+J0na5jIUeAu)^FI5t!@VV5{sDyIE^*ZU6qkLR2<&u71i#64F0I!x4T zp-$^bvN}S%_bc`_sW-{@8Z2Mba$&lIz;ALrcpgulhkf13^N1z5e{sg*8@wI@%k<*; zUCR;E#nQyqifs_>7t?v^uUuPxZmQaIf7##4&*_ zbkzy%wq}`@xu^u!OU0=pgQKPrf}luOhM6Vr#{?IR0=hy!dvyjDXV3Y3; zBKKC=V-Dh%m3g(f__MF*9oXtB=IYMwKdv(;k0#@_1ro?CB|9 zM65+DCxzu_J?o8zp?k@$UrCFr7pA+GZ_krg??Cnz6MLOJ_py4GDI(UL*V{^7({tbd z;hxXh$k_edi-`CJmhPvfd-E0+A8f%CdED_3*L_~Z48@fxo*MS$L#j6}0j7KK^?LH> zi>sfX+)opjOKh8KUa@xfv&OY{F|T-bh*UAJ*q&!^_c=Be&N~d*FHCt`60Fg+h4#I^ z#ru?791p2^y{qP~b@ZMD`SKLi^iOUiT3DmnYf0ZkBrrv^u$ZZ?J!%Bz`*#Q#?p0|Dr7S zHTLgJ$^A^v9mRT9GuqmDXm@8_Jly(GYl-{<@L zJ&)0XIw*Ot6|M~8_9z#-h?C6_n z6}H4|$y@zDl}!7qetyVI{5C!9>C%Xo-d&>VtmsXlOug~Z{({R4btsCjZ ze)9&a#9T8_&w8@M$R1IS_qoem+x;3(uErD4c!Il#=fq>BM`y<%mK?p-uh-`4wS4Al zr!?4*k`lkBB-bQ)jtl5pzCp7<_kVVdIXnCYfBWzuy>D3W8`1klcY9yCm*0D%c;~xh zd~-Fn^C&L+&NXUmgf7nS+}RY>(Z_+ti^KYtE}Z#-o$fE*A>Fug~_)6w~)Qep-wMT z#NRmnCOU;C!QT@8mh!iZzZz#BZ2Mr_2irc__Q7_5d7r-@_)GHF#^2}sE#Yq|f8RR& z@$Zj+fBgI7-yhpS*bc%r1UW=y(m4|SNc1BKH_W_ehMCUp(fkePZ-jZ(9An-v$D)rU z+(^QWMvhjQbmp5I`PPkO4+tI?~`YtU=ZYtU=aYe{o0dL4QldL8-#^aX@jfZl-K zfZl-Kh~9|ah~A9ejNXjC5Pc!~Li9!Gi_jOLFGgRCz8HN8`V#ad=x3mxfqn-1QuL+h zOVO91FGF5Oo^CJ`-P=suy@S7d$m>1kGydZ4y=J?)m$JB*Fb|U72g&afl*1F|Oa9{S z^X5bIJburkZ!#a7P3W7@UnGtfiQ`4|SGevKuKP3B{h90jjO~5?KH#s7aBYNZL;sj? z9~15i!hJ!wFR=ZH|4+pF6S{HUcZ~A`e@XscHjdNDah$m8Vt28-*j;B&$LD-#d`@TA zPi%fF0EI-Y}h= zFHINX=t8(I+@p*0mf6GE;&$b)hx3i;!8QE|A2Q$9JEk+tHT%M-DT1BN;mV_w#mbm+ zqH>xtu1qQyD3>Ug!EUBSxeE3&SHY-R2lq2~tNlrMpxFWkm^an(F6?YRS4*)YF~neJ z`jjxPOv0#Hp!yQ!GC0KCt@ekN5;Dr~kbYl(v|d%LEK@r4vhVr1=)>Lb>nE9`U^m*( z#M)`_U!!N5X>K*YWjf7$h2OxO<}T#7OQ*R_{ATGix6cK&@WZQ`-~fJ`beelNzey@Q z5B6_brCberC$Bem6LV)H>4B<0scdx@oxIkxx{qAE-n{7^?Yjs5IO-udu;dAImGArd zXN;7?X0r}GYFd5rdy%a^`Mt+2uKcd#7FT{xato<_9k%jYk6U~{o`=Qv_9|h$gz-`>!^6dX+);#a<+mZX zxbiEITU`0|$1Se>UgH*5ewlHLE5FFN#g$)T+~WJyW#0%_kwV{37ySf3=@fFd_+C`| z!i%~Q=T8@PcHZ@!GQXSo+}GCF!};9z(Z2gRtv>nP%vPWLg5k&@R9Lc-m z>ylIAOml)q@Oyzd@+;EU=X|lpFU^xV|J;vzX_$~-LUva6gq_X4sviZ%ImK#;!2xC> z?51sCvg7#wHF_FsEjtyynJbh$I{p>)mFSYYHf@vBNKZHOr1D#3Pi-?XYKQbFi%1D6 zRNt#qkL$gX%5`d4rD?cIEiD>DkT)nVa)P|`cq!b|tcE>Q?`^I@?_;iq`U`$?X&f&N{wNjhOgH!P3pVY{DG^^&@`N- zVb0Mo=W7fX>a~|EuTaHGbsUej}zd4hQEGf%;XOe@@=A)nGP&uQ8=X*_Qz z-!d-}X1m7up2qf}rr~3~?`LK!zF+FK->bzq5oDTC)YC%_9GsqsrR z7gs8;(Oj(29IaJ-z1r{6eBGz^N0l4Y_bK(=q8f~T&byQS8Au;mD*`?rFIs(Qafk3QafkyQXb{zO6{EQ zO1)g@O1)g-N{w9Z&VpCEQZLuI(u3BxQad-gQafwiO1R#YI=#!4n!3-G_VbV{b^53) zwf2;z?Kw^DCQbj#nwM8K7jLP3yXx<${X-4&nd)Dv{*8wDUc==0r1XM5$#2vrdF}Lw>60?wU+o8~eu!Q*!U4--(lg92ZDWLA z%66n*T1cs1%IA2$VSxiaqMyWyYju_Lh0fz+kg2Mv)!4ZM} zaAZJgzce5uod^8!QBs{_MfePATK zF(55xt;V)q({Pu@e_ue#_90FAqXEg|hJfVyDNXHjnu|>VDUFvk=2rt!0&i&g-_l%f z*R;K-Dfv)S^>ILI=QB;`mjNl;ZvxT+zt{Aepwx9RDEW#8FQUJ63XUd)Zv-X3Zv~}% zwqvK)1f?WD)R3R4-l&$f8ghMT z0(ZPmEf1;hhLDu`Q=uvFxzH(aQ)m`^IVA1s)len+8=)k8D^v@&hZ^B~p~djSkhFo1 zLrdXjp|jzaq4VH3A<60YA*p>6z7XbwW$q4!SD{D4zk!{?SHnHSYhaJ?O|W$n&G2)#c18Egtm`&k_R3Z4=EH#{r+6FeuJlS4U& zL-4||^s-CB`RJF2_kdT1d%$bLd%-o~{osw^{%~#h5V$^kIJ_%76y6t>S?{6naP&vR zBjJXyw8N*uqtTxW{{n6bOD}slJRbek@MQQ#cp7{wEH%D8EOq@}_*5((hAZI5;p^EA zFy;}~Rs)a`^Si+!_b|7pEHrni>}wuSd9c}{a2TIIb`9I}=ywbLOjzIA2y-G#V$HaCNv+!-w@_n5H}De;Sx_(evX zJBwS9!<{}e+K`fNkrKa;9l>qpiBTdW&K8wB%v&WP+{2wwGek-_kvq%{Gx{Pm{YXte za+~p$iap}wmlh$1JI~D!Dc6-CC43CI!+bKM0x9K`L~8jVC0q+q%5fdC#OXP62U4zU z^Xwu|aAubKeD?YfQm!vT_N5$3ka{1a#1lhG_zL7U(|5GUt)AIVea?%=ieKw zih2GONVz`gxtB{g-^_B6moa~c+~%8G-s1W1KuUO#GA@L8b4%{C1G&RoQr?Cf?!0xX zkJBJc7c%0!ST1f2k38LX*We=LaK|?*=DFp3NbD`1T!Sp9zpX<`xDB4W5AXMhy#y)c zBXXxz%}9-P@e`C+)y3*Ol-o z+?14bm+&hPJBkaUUM>Xe);Qqr|U?bO#^_Ii=q%xfo$ z++p55xi3=EBXX-VY^um@&Wlq^kaEA}o@_-*dAE5o#Mza&W1g%)?l4u;mLv5#q@+{a zlFp4tN#{B~K`G_E1G&Tee%gD;>Fj5;d3IkPdwpNz4)ejZ63;C%;v95}NR7|4_ubdV zTY}W`@np$<*1ZE+=$1_1(U<(u&TrV?+BYH#-P5M;P`PS)-+tm=HC?^|N91x(wjeJf zpBvTv(DWTD-{vzc*ZAb|hI>h$-BBWd|Qv74c z;m(YB(zA;cyGV(z#j}ePyGXIGLrS_@J%5qnFH-#5JiAD-ixhk4PT z>@iO!k#e6FPpUOtc;efw96J7wQ!j;<_H`x7d~9#i+9Dn*JrsqW7zMT)yc z-Ts6~aj#SNUI~%nZdLc-gvgY8hbc|8seP47v4;+q^!zR%Qrt!AzBM5-<(BJWYTuwz z?Bd>GUP~m^e!yIjVsBITadSnAJ2Xh*pEg&d#;5M;xka8krtUN6iWL8(y04upQrs=- zeqgT1lzWGHVeUG$_pA~r_6ow}c?5-ILhb^oyGfkBh`PHwC`I6xA1uu88=#ynhvD4 z|KZji%aSrrwusxuc<0I32rqreOPlW+oJ2}|BBlSdcy5t8|9b9qp1Tz(_Z8XbJ2KgN zjF%pyT;JxoMT&dfagq=2kBm6CCq-(ykutuvdG63in_rPKzP2DGT_R=N6e;7YNFDc( zQXZ{HEe~~bf253~p<)|fkxIq~WW?EUnn)R+L`phD%J>vRN_vx?Y(aj(`e$91)cmQN z`PT~<8YT5UI3ZHwQ}-M5i;yy&h!lH^+CP{tGUeW3zMsEN?Zc`>ioI3c)l)>K+&j#e z>Neccend)p2$gu{g%o#@=N2jMR?jU`+s|m}-%8!I7iorlyt?A z(mq6rJBgJ1iO70o`AjA43>k68)ryq% zAyV!uQrgElWQmig6RG+3WE)b`;kiR&z5F93T#@G%srUEXG0&YuZuGr&vPiw3x@+rN zJa-#X>m8}}KF+#BNUe9zUF5l2J-0~lPfoD$u0sxY7S)NA`-qhKZbM3ahbCIN4ypb~ zsqfe%n;(&q{-oy?sqS*Ge|mDAO2#Lo#M6cx?p$3Lnk@2}x+0{ES4pIfXGk3%JlTqr z@)RlYw|Q=n;tox*{vyTw9#Yq>>gKunBpY9mCo7TSpF~Q$BIUXk&n;5i>pZte^*`Ch z(}I+Iv?8TFiqw1|wce3hKS;SQIn}!lQre}srCo}YcG=?jiOFqOd`G_Iq`lJ`G#gpqi+3LwQPbO#Bcw4fhrrUG3BE{Y2xkZY*Wv28y z+AC7?i_~zlth)`Fa!Yzbv!&c(^&-Vxgp}(s>U!(?kWQ>=UBOe<%5a?Kp;--iueiASVd-)FAK!;hY=^7*6JEVtKf@T6(6;m^vF zdfyA>y32=eP~I2L^M^l7KK76;A9VY~CXl$~CVkw{-hdbmiziqQ{iuloORxl+%#yohkjaN$AWbKsU?!ox4S z1lssd94dFQ*B%;lTw^SIgn~X}Rz;e)%gxdA_11O`TD4*e!;4zd< znc3T%M2M43A5%@JI@8xQntrB<5vhx0Dn2=hL7XyYB$kIhK)i791#8*Tn&V&-deiuu;e zU|(kr!%T(w!6bR9cfN6WkJZont6|<*jqU-)Sk-C@S@KI#PbZ)Q60q|R_ZG!?v;TIK%T)VUv-g}j&gOZOkV zss1VN(0pOecE22 z)7Q7ZbC9o}Gr)I%bGWa+Gt_sWbBwRZ8SgvDndCdzDfb=XO!gh>oa`ImoZ>soiPP>D zoqI967r)#0GI&GdYWQi-YvCBRZ!Y^i`sT8=@VSfcfYV0Z2k&bU?iY9no;_PwKV4$@ z?XXAT{Cz~fupKGGwIat(S{lvsz-dX&669^rvI5 z!J{;Wqb~b1`sT8ClgsDHb;j=C7wDBv+RPe(c3hSk83(N zm;HccbD3`-@BJ^6kekaw=$p$5l--rRm3@^5!ip;ngGF_c=G>wo=r+x<@}tmgIvXyO zd~Gf}7E9#PQh3XG5`W7odlwtC#A(Cde&R3Comz?W($ewhS8ECM*4jBdF&WE#%jH^| zFPqvcG|OTJ@Egup zihbWzr9FwTQ7TQ zdD_zZ=NKEqb=+&od`Z>*^KU{gxLEXOw1ls?P}=aNgC*oa+DacSl^VQ5>vW~Yzqk6{ z7?Chbr`?9{cURpF_nsh@M}`Vt8!kNkG>Q37zj_ega<#lOOzgHaY{@@zl!Uo_@neKp zbAjaO|BsZ|GO?wxbKY%wY>Ca+TzAitbZ#!&NUAoMy`X#rZrAd$byT9Yv!Ax!P1+wj zFME?PjfKy+!MaE=RUCNXbBm)L_+rIFM5}ve%LDu4uUs#66Pq^=8Jy% zF9yPKJ%ld}k*jRX)x|@w>|D;a<=e7tSbQ{LUg#-z*-L42^wkQn*m8URK)L&w%I;bV zD|OtqrQQ6SOdDIPBe~_~vXNXhQG1qu&}j5&hf4~l_m}WC%p9#vztUR#gCtBOA>mW; z`~rRAu`(l+DxVrP9?REVr@$Xerb8QlBoRkXT{RcI{Z;d^*sJ`5B&7dzDJvWPAHNjc zKWG8=TYPf&Sk5A7eK%?fv&-2(=!~?lf6&?JN90Pr9zRz2x0S*g9V=`a{;A{b)2B!- z#%db~u9CaFrnWZ^nLrj-soNlw6EFO=9@B_Lr^4iEjJO`KoU&TTggj zy@Y&Z#J%XdYUdAQUpw^)IR2!k;Q^ChfM03PdV9habXQBP<*e7yH%S% zIwyWVUrq-e&^f*T6_S@r)xK?v=zsG|>D^QEDXa*61vmckTbSLO0>=dhrTSFMo^sX1 zEAz3ubC#t4ZY_t{iDI`s?v{|)U-gUS>|gIm$g6aIf9YtkciK} zK3Dt5&|)d8AzG??PZRqq-6Xud@3$90-E4%Yn6 zb;N$yo?>rYBzKId<=0&Xq5q&IP+2ex{pL=>9Oc_O{`AqYXr+!$`>AD!rf_Y(gzPs> zYX9fYu#T4A)J923_gqO;?J^k?#>J&PZ`CrKsCxAQ;#*cDY}4B8QY0bMYb5TTJ-gX> zY&+?^Y&5<$&i@>n4QcOd?{dQI6S%f*&x!D_{Z5AW&656=J!|yS61H>4gMLZ*FU}L5 zuJcItNMc89+oy7LzP9sAc>kHi{5xHvzN!83Pf9!Qe6D#9YHY{4QUW&Dw&k>+RV#>R zbJ=Ooj`{mtEM;35l96P+)?+uVHLKhDvc1*LAcOZ@z_l;_O72pj?fEsI=)3CaiwL>9 zp5AiSQhYZ}UJh;V{(gQ7dUg-B^PTM@jTLg2?EYx&i?kfFd&kHIDO=m-?NyZpD~b8$ zPQo1J?%L|wd>BLZdUm_YZa=o= zyw>;kg#Y<%#!w}iFCwz=$1Xj_6UE6ep-N~xA0Wzuh2rZ#O$*j0@`K*-(K_@nr4 zn*2wYs`2O0cUR+ot?pRk)>1r6?AbM5S@0t9+}uf+quhP{N|>KtzyGafUnREen(e%7 z8y4FJtZrl2xi)9*|1Kf_zpKp;h;4J(C(zdBdM$@k4N9*2P0Q4dt-)TpLd!i+Mu7Kf zg?*-fMab+m@cGSRZ&@TO;ey5A;hVi?PK~b4V7Yq`W|zj!&oalB${M?2aRDK-*O>?F z$}<&PSB_< ze<0j>y>av+DWBc7VY{Np9<}=GYQcuzxo>8->gy9@u@ z2v$nUHR<-e)5zh2iW_Q}ycsbxQ1Ue#|BG5=xt zRQUXnr@~ZklIJXYl?}gh$j-fF&6(4;lB-HrodyS9RS$PAF`qso*b#n{u9Qyyh0G4) zdI;}cwvek9NbsCX9Vn zvR7rVH{Py17vKGLf6T5i{@PD=)$AH0t~(n$uP(0CapRx5&VQ&_?ln)>pEmx3E|BzC z{r+=BAFQjm(wqyqSHJR0Vg8CMVdsT%?Qc%k)K&^l()#*xu;kswU_*}69T;0y*}n5A znIOCNe8U@i)bbtwKK=(y4LkpxOf8g?0Kegvv0>0$&7OBBa}9Jk3kYDzmM=Y7nhkYE2c1y~+)I$?Pny6mTS#`1*I z1?H4r{g06Eec=ucyWw52Z*;n0e+s(njd#aB0tVT2?t%Ro=(1Pd z6Z^3+XrAR8DLR?wplgmJ6%IS-h1gr2-q@dqt|_K$95V_A%?r-n*f&Afl(3ucu-m>5 z_RUTo>@Px>z4v{wm%$*r)B9l`1YI+R9e>9h4})f~yFd0J&}E;#ANF6sp!uD90QT#k z%coBIV;>9UQ=123zaF|~947@q^H=vEEIXiUPUOtMG2>y-+!Qzj`^}JFhcky_p9q7d zAUFVfC+M0<<}fVP!GTz6Am2d7w;4EmD*ABjU-L-U$$SGj8R7(j?^c9C^KEbl_J2c{ zQ;Z|9ObQLfQVv}+mHKhaG>APsOzhA#aq1^%E)E}!WhHbuix^JG3Mii$8i9QkbWJ5S z6Ev$M$6~n>y5=varWYx$H{@ixz2p_ z4fHU_JPBR%N6v#>&P^A!@|z^i74UFp zH5}wz1qVA<<2wYp<_PCn^r4Vm$ypG+64Dbn4{|vzx&g~@=yGaw6Z$dG<@D$l^y8q* zDbhMv%(;=v=h<(E*Eo0Ldo6U$@0`2gb(|i#hR=M%>p4Ag&F?uoayeOggpfBvmlLMP z;LV&Rx#kv5l3cTvvn0o?gRZ%iGbM-5&OeR5p0g##+zwsNq*~#foGv+hD*pxayPeJG z_dwU&>%4@1AEcI@E${(nE0zZ#wd}kGA9h~H@(0Lw@VIZn12}_nIhpzkJk)&$4shRv zhj9)?d2$lP2*5cMy_Hia*No>3iXO@d6yIXV85F(J{T!CNU%<)kSFoA$D2J1(uhAEA zF2%27LDwwde2VYfg|0c>{Q><9=$fURSGk;MIh;?P$yt@l$(A23-^TKzH<=Zrlg0Hy4;a2w;_^Nvxe9bL}e{xIU>+Wd6zX4soF=Pz5sk|^a!Ls`s!ewZvpJ;YsB6Sx~99Y86N0c zgrx|&<{;k^c(CtuEQdf^mv1Q?<~tM1QIHwmSY(Knd5vb;IY2*;BmedIMR0k zzQxcrrMyqVwl=)VokAbc^-nR-p25FzZ%g`r4+NbXd^huER>01q_`mVw<4Z7wO z-__{Tp=)ONu7xvw*I_vox@MN|di2?lxxjY=`W)z*3g1oWmC!W_-!15KA!EL89h}c6 z`x)DPx5EX#J7I(GZrJF%7yg=W3vkQ@ke2Ct5d9)Z%k({rz7oXv`pWV=)ZxCHolGM*Fi=b-_!7V-?Q-dzE-%-_X57RLYMcDHlweHuDRX!68asG zk;JzJ{VvEz;@gUT4`d|qy@q}tWF+yuj{X2-zVN*XAM$O38~Dxx*F5Qa2maCbF5Kwb z0iW`{4`1?q0AKdCaqSjJ`}ci>z7^8`eg8mz4brxKpTfWRK8IiXzJTBOzJfpczJ`0` zd<*x^`3~-r^8@UY^Aqf!-^K;t^VooHvdex zo^K$a-u-dXb_b;1{T1kULF(O~fcN;Tu-pq>^Rzz+pYhL!@B3@u-~4s(fZPSJe{LhJ z%58@8au>nda+kpMxu?TVa+ktSbI*ha1(v~s1Iytdffex3z$pamWlxBxZ=E`m*g zm9ROm3jQ{587a9MGP(w?K))8!+5@ZMb%Cp}tbw%lz}4u#hs>>kYte6ntXKlqp+62? z^F-i!^bL@<8n^-dkC3(+xC#9!NKON{z*ht7;J*U5!LI|i z^zR{~Yv5k=A0eY_;C^%yydT{OJ_z05!&rQfnhidJ?uU%A!N<@8kTEv+1bPTE#s;5+ zk>ExwQOFn@d>TC;vTg}Ji#`;xZV9%c4}+{*f-j&S4H-p)o6$!=M$zC)=*L1v(cl*J zk&xLrxD|a0bj?Y@*Wk&)*Rf26u9+5m6a5tEn(4u9a7OSiSY|@koEm%w&I-PZWj16~ z4DNt)g73qM;0LfW*oJQc@=NByk6=~sA8=mqQE+^L6kC^h+V5V(=&Q%ORs;(D5-ULgwqB5B*BWd>!M_&)=Yr&rIj$k2{JE3dt3ho8(4(@~H9>^FQ+!y^m$QT>!i~ay)j1Bffe+aT# z3-(9<17uAeEJA-2(!zrWqdyL5;lV@EH$Yl=@G$g0LRxt6aP+4jJvulT{Tb+*XM;ze zKL=gY8axvHdFYxKf=8imf{cg3;pi_yM)Ke>=r2RY!=QXj{}sr17%WDA6|#~EmcT#p z9T<*z9kMhbb<>;S4Mv~wZ z^v@vA6v30x{|R05MQ|GWm(Vp|1*fC`3(}`TGhvADy`WEp;xH1bfYDF_=7p+YKHq`i znu5@L*eO&4Cxq(Y#LxnG3g3!B`wun48KFgRW@rgKHFP?h#W!TQW_IXI7!NIjm7(P@ z5n2J~@|_v9`A`e24qX6iLKnf>&`MYrS_SJvm%#<0D_}!tHEaxB1)D-w!^NR%;gZmG z@RyZBdP?YS^vfYV zC3G+PZy-G-bU*r)ke(8H5dF81o)UT({TfJ52|a@TJ4jCnJ%+vp(o;fDp#L7yQ$kOo z-w5d`p^fM_LwZW+Y4o*_o)UT%{Z>d%3ALiHhxC-t3+Q)1W~I<(^t&KECG-;dJ&>Lf z+Jb%`q^E?oqCWs#^JwTb_*m$5_;~0|_(W(M+z|Q;VV;DnOhWIVZ-lH&Lhr&Ip&eM> zgS5=h`|zXC2k`Sy8}@%fT36^J^e-Xn>d-&nccD+=_o2_BFZ=}z@XaDTw?f)m_-phq zq`if|MUO&upTggvcY&;A!atzz30XPwO(d+GAuH#wlf(D=L)Y{S`_Owqc9z0^*gG7+ zvKM3(#CMiBW*_MC-6|2dZ#WOje$X|2!v*O3L)Q!qcSb)F@;kfa!7j)4@O@Od8P{=fxZIrOcy>9{XEDsUHB;U z7RYLi?^$8x3|Tpck3qi(vRViq2d@qn!)wAN@LIlqh1EiM47@HJgKNSk!0W@~;8T1T z3*%vUB77!X4xbHAfzO9ehA;5#EUXE`)8XduO!!K87Tg++!?*d47Dl#k0&Wji!FR(+ z_(^y^>G>48=Cg1O`sa|{k8mCO7tl3dh8LiJ1zBT+8_~aptaZc9=-)zGT6huqcaWAA zUV{DuWF;Iv9sMWB>%Nht=niC!5jhjx2U%l8mZAG0EikeiMk6a=UgSKOA8COFkqZdZ z3DPnn7om57w9Lp#I3%(P%Mp-gw8&-XM?rQ%B3Hmsk=0mAAWvbDtI$V7T2$m}I4*K6 zJTY<|oEo_v-)WGsG;#y_bjVm5xe0wHWGs!`f<6l}mPXd0$02Kp$ZfD9ayynv$haE0 z6MZgZT#eif=SA+tl7zI+$o=T^A){sFLG;rh&r^|y(N{vAry`G_uYx>JMIM8fMV^3{ zN1lXNL^i_TM4pDXMV=+(ddRpGX+^&SGA>14K)(wzE=4xOKSW-_@(5%UifloD3^EEu zwxT})8HFORp+5;3g(9z`Z-lhK$eZX-Lt0>D8~U@*HP1!mouSMR4e~RpY zuSed8Z$v(TZ${eSpCcc^ZzKPJ|BieLzl(ehzmI$Ye~NqsP4sK%M8Ab@^g9@c{s4o~ zpWq%*$IrfZ)Cc#C`u&U~kdY)BK;Iv-M-&aA9{^eTMbSM))U9l2_v;_SU$jloZ z4KIz3f$O3%?6*Q%SM&t*^^m8n=s0+9bUc>(AoE&uBKiZ66=1X+J`|k-AC8_3{}7!9 zABj#U%%hN5FFF(baY##u&Vt*baV&2^o~EM}=x;;Dt7roLEm{RXh$gXr2w8na=cE4} zG6P0y;K$KA_>brU_(`-8ej05i%x94KF}eu-pO6tIZwY!7GQ#AYj-C%0Ve*!ucY=&C zd1s<`fwZ)|W$1fC=Dxh;uv^{=EZw1NdgPsl-V<`dlGg$Y^De;B8@gt%yo=!8c`LE( z1DX5sR-x|;U9(@_W$1k&yGeOhpbv+PT6wF{kAbwMysOZUgS4f*tI>-gZ7J_s^b$y0 z%DWDIG^8!%U5`Enva^(T19}Xy4$Qj={Zz<0Fz*&PJ8vC~=iLV9E9)V})J%;ac$ZVMR1YD8#Bs@27BRntfX?)Lz zw8p$=;jMYCSZ;$ncjvu;emmreBX2YMoscJvyqD1LhP1c5E$H_`P66_^qTdhMAI^IX z{Xs~3%X=ODVMu$+dlUT;$oQ7G4gE35+9~fZ=p8qu*l>aRpoc|r1 zng0WvoBtDWRzc>1d?%N=05TWk`_Sh@#({i4dJSZ)k{>{?gRH&tL+A@2qeOlLy%91> zQry#=zW$?pd*$nTHkLdd9+Uxa=!Wc0{C7~Y$ID7-)aF!(_J z;qbxy!SJE{BjDrtN5UuakK(EgkY~XB;qZ_7$H0yG$HAxai{aDxC4_kfvgXMj4PVF~ zgJlzBwUZx1e-ZM;mwy8K%aA9&{BiJ={PA#W{zUArLguFYa=0yj3VbX7WcZi-Y4Gj* z>2Q1gO!#j8Ecn;_I2>G1!L>smV}3ybeJEtiFQ`Hv2HDLhNTMGN+07`Jk3Is@e+z2R zkAw8zf;#kKNdGNZfL;RWzXgrxqappbpc#D(r2iHyLXSaK!UapvPk=n%6`T%d6fA`^ z3(kb67A%9a3YNp!1uI~@;5;~|paoVGTmUNzE`o`Im2hssDp*x;8Jt&e1xyyKhNl%= z1?LxB4XX>Tg_jgu$9-2p=7oam(JzCnKniX^zXI|sR&WzsQ*aBG>mg571?$jnggjLh z+=hNL%%w_-}v*`fq{< z`EP-T_}9S!{@dU{|Lt&)|4ul>e>WWJzZcH)-w#joKM1S+55rpjBe3587;NxA0h|0! z!iD~gaIybs_)Gt@@C<(|{FVO&c$R-NJlp>gJjcHUp6lNV&-cH^dHaq2*Wu0Nu|K=P zE8(r=u|GS&m%%&8V}EviSHpYAV}ElWdF*cd$xF^8Ik; zujHt|d5;|RXFs_Wen^h`o4=Ez{(S50R`?0In9si7GI&XFIlMHuf|K$uu~f6evmAbd zrH0*-WpH6=Ib0lC!P_2x2)zp*#a_#9z;d_&d!6|^_By`VbQ$~vdmZ0zx`OlS5#eR< z*zj^VGQ7ex@co_3;2*Ix@SM1U)9itfWpGerIUEvM!Dk*DB0D(W{sZ=AR{qQ3VYjZc;lQqK<`r{g*Nfn9yRPKZpq;w4nfJ{n@B=fUdmEn# zJ*)eqK$|(c`($`d_mkkc-KWCyyPpDo-F*hUu=}a-;_kEIja>DyaeG_@b9$`glcWoK zw8`gqd)}P;lR33#n|$=G=S8r-=StYna}{jrc^O>T^9s1Q=W6)No|ohr=Zv10!drV@ z4%hd*GS_h)@A8cF zE9}&3J?zr!E;gWt_UZ$N_1X^}-D`h1qSpcN*j@+1>Rtn3ZLcA)zSmG5!#?g+20!U_ zJp8QJiGf@vTzC<0PDBe=!u-OYV5dUI$#o7ad=vekLLd4eg?>1oFaQS@hTx#WZTJo; zoC${(&Vs`VriOI>D#2_;&DIVo@4NZg0{KOI)V6Y~F z&$_1)ftpSPdO8srgj-sFtJp+fky{PXm<}JBjtMm#6M8x(YbOS4w91Hab(PK4iDOMw zqG{IHl31xKC)YL1Z)}Q7p0G6H)!rh3r!*!SJWo%pjn^a^>*E!PDU)KRd`V+dqGmvB zyctzKc@nRdEsR$;CuYq`c}%UT9#CE}FHsXWlM?YtPmR^iO*BkiQlH2eDyo|+6Q1|z z#n~=$Nh!xC$LCb10>r9n>l#vyl7TVIVr`WUV6QmuYs5+^tryY_6`huJQGWTC0s-oTzA)E)cJdH?%XA z&apXtf$bCAPXeQZKZLJJpi3SEk8|jIO#Z8kEjm_0f?QU{nUG2o?M8gtmY^*R- znkux}#47FBQ%AxQI3&YkQ;zDClBiD9cp;=?esnSR*!9r1u zCK3XUT7r`XDH);n)iX-S5TZ`0f|7Wx>e^0Klg4VY>pP}{&bWAeJtIb@DhCu-b_j=G zb4~4k44ApRae&TK*|D_q%uF-cL3ZxU#gz-=wG|1Hl4v4DD3Yz><|bydiUuu%@&r~X z>Yc6e%F0b0?gzt6<%ZQ5Y)R*dYn#$ zos_87!E5JOBrP)Ir$Txe$Tp3y&346VD-(;e4HCnoxE)kl|7?Dobk5O5U{*HQIVXR#4)9|F|AX{Oybrq z^-Q`NOX}(+m?VVZILqQCqk}PXg|>ffv!iJ$OX_75)_yBPx{QA%lA6)A(qU`^vbFPb zLQCA`vZ|1QtuZ@}ovo$GMtcj%!nj03RiZ4Olv{ck$Tr0qDUM`St(1$*2#L8#(WTQN zBm&#msuS^sObqR8<7?YFC8e>(QA?T<;~N+Oxk$Q7d&}s>^-1xWlvvQL%IJoMx`xK_ z6&1}5VlUTuw^`I!V{vsd-iT%+E~%~)hg7;Ml0@ogN<9UP-OFN@MH^endrEDCG<*UU zvus(IDCO=IO?3@RSkWb_8q`PbW2dsl;<hk9LdK-oGqqIW;pGZ!LT58x+Ypq3weo|GFY!ZKQ z(Jj+%T7zBKdkYq?pklSjCS6zI_9`;lWK)-Ik-4|LuDPKiL3^lVsdiGLp^;v9VqHUx ztj~xio$J&}m5CxV=t=3Y7MRyiSNn59d*zdTMRi4zMq0}X9jQwhyT}>Sj9VX2R2!pf zJ5?ET7(!Cklu2b>J70~Z z6O(e-^?a5mE31@WV?##O!c2Kcc1O|oQf|3xw!7V|ZdXFZmGOES%>disQWyS*fO3zY z9as|3J}~9l-q7JznT5>&TLeENNwzosjDV8%pB-4z-aasCZ*Ryn?extTRHxOfB{Q`w zO+QuG<%}*Btl?~X=uiUL0VTmdJFq0Uec;BQd!JY>bIH$5(9aGm32Gmh5^Qg%@XEkj zu+xjA6J-X0-4Byx44GayEwPGA*7v_2yKq=6L ziAvV*j5d-$I}e%E^M_1Aa@Q=cvSdRePZLee4b13X@W!Ti12zq9XD*wTcw^%ti9u74 za@Zx=gp{*3v55RLDW@%xjpFL+x<#X^LO-iZA+VA*y<2-34nmS#psw*L@R@J;mds%*^a-chy zYVh)qF%ViG{?ozjl7ZUD>?)4GiU0`v|FFGc!(+I`Ke-_ z^!}5RP4mVk=O<(rg>_>cnr@bO`YvYg3GoKTE?HH{22>(7n@P7|<4sornIMw)pAk%o z!v>pU1=THk@{{YRfC_8!cHOLFT(UM<(_G^@;)^qmSYugoaiUVLOUmNg1}UyQjh2-T zZWT$K-JjC>@Kn1|Wg0be5<~}04PmvCd5MboG?P@LYMeD{i5F;0qA6?9ZG&U8oyIyP zMky=ns!VGvdouxaKO|v?b?w0==}}&tb|A6gwd{1L@Z4Ft9r&!BM?2m8v98H=R?47k zH64>E+0wN-`xQLPt1bg= zleIRs+g-D^^dKkcBWE4PMol$?UAtiN?Ag&KX)aC3zK0w$okX*hOC{+$TlE>Pw5~aI zOV(J{K^e+|%Q`04WrAe<)1Cw@XPxJzI_V8E!U@@!Vde)7y_n!{FlQG^gl&zjw zvOF;*&2th~(}reM79MQ1vZVCF&@!v*s;pxy^FXy{*G)C6mr`NuSk=|0ycp)~R;D$K zOVrFsG+14hBwn!QhQ>Nimz-;oB+shooTi%gGHX0ON&95XUSgfH;Us&K)+MVmn>)Qs z4c|)#PU)w~b~O9@#^TMo7O;4KeC&lK!lk zmr?7G2+5yy%uOkpKi0h(UV_LXSRG@$Q_Pf``eqVKd&`AWDx1=7xi;G^$(%z?rs5iH z&p6n;oE)!Gqprejt5mm6RjO6g>C#;b$F6A9EVsyZYQbh1G(v688r&jd4A-RkvI&1Ef9`krM9&Asy51{1)%#8gh^w zMe5-qeXsOdC4GnXmNAK@_68b{UH|9>Qi2Td)U!IhIZ)=7>>bb&79VvrQuB=HJR#Pz zs+Gr^l4>3y^};$m$yBveW<;$i5-Zz?Y9+KvDIX2txuuG;-CiAP*n00tN;U*p%-7l& z{-FOF=8_`<}5I@a#$+Rgo?bSia^n5>G_z>?kKCOJ4M z9VLCSRz`2R<4#8Dpz3R9DJqS}JzW6uYJ#1_I@)yB>S!z-C9|+8XUkUhFZ4OdZk?uG zBv9tslxKN+C%$Pf6j|M*-S}zjk`+1NHsfm(oCg7~R5B}`0lN0l9z7vhPXKl&RI&j? zQK^S2=^ml37%i_Mwc?a;joOo}pT1LZLcBJfjzJQr4k^>LBh^d1W2%a@$BB%&oKvJO zs!S(zW!QNFG&eJQi z(!w@#CMhY0O-agCmr|M;zP$q|y@skw-6d5ldSIXOBw6j;8HeP^+YU|NJ=;ypQyVMQ zO9uow{b`uXzL6JNw@*}0R3;fYWX!RlIjf|BN-gVa1FCt8?yLag8mrVL3$~O_YO}X4 z)W4F$lGLm!aq6>yC^S&-C_^5s?Cy+Sp>>ryAySJziptTvy2u$z236CoRK~{Y#9}qZ zINq#f6Hhi|mZ+sk?#II$qpZq>$+~8q=y33OT*4bc#y-WUDi5x+rf}ffAg^nrcHL~3 zNv-8Ly~9hAZP#|*?oq}qxy-oikdO|nRZ$z)jm*qsBo*Lo@v%FTFcX{WI9G~Ql5JUK zHKyP1udPhoQ*IJ#v=72|%*?nr+9``y zlQ0{|>Ux-&9*8o}K?AHxeZ(8MWYIh}&}gW15K}se`|87wN{LPPaO{*=!V;ANVb9s# ze>Yy3Yc-5qZrAa)yc$cJ8+cB!j|_Iy*G2uVeC?=j#<8B{hK+ibQDxJ{D>c)w6NXyms!Iq3QkG37Gfn#)86K2AWZ%Fd06Q_@QOsU)r?y`ic#0 zM=kY|G6Zb3xib3T?2)biBIBZI5tlS;-E!=Z=+gcxp2( zinK4a$m6JP{>lE2RWyn5TIv1vX-68j89tAt+%wxoS0~4#mJjWc6YQfwWF2^QJ!dG6swXm-Aai!<0FfT zovo#bIn7m7?L*3$L=B@DFWeN%5H&Yh)vVhCnaDb{l#Itt&+Hj5iqLzy&)A9^8+k^o zUNSk^l$}=Ta@FxAvIfe8rDWwHGHX_9=a(ME+F7%%D6Xn%NJyv11QWaZ6snxGa-zlN zW?e1So<32}+(ZYUc%}ztd~~U?OAluFUD+vJ`})}~J>{&4%Y{qLAwi5rMOGa)b!NoHLJ;WnLBy)Xm=no=Jd2e>hzc; z<3-vgGq6?h{$ILl+t!?Ik!hOhpyRSi$pp0hA>+=ZTc7cZ<+YiNulEWqX`t|$l8G!Y zJ=K$g8uo><%w^T_sw}6MyVB}vZ^5fO+7seU^Rfa-<79_W3R@mP7ps=#uOp_e|5@uV zv4;?G>*aUt66O*w%e} zTk1OP_q96(mP6^RVH_tW$yi5XowBXQ4LX*C^^m}lX?YVZb5VN> z7wdyb<_bxUb&ZQJ7DqYn9$5oRZaE*yge5oDp$mwVgE-S3`uciV0~4LR$80EOtJsr& zt50rN!X;Lxh^!)s&z^cT!|e-nw zvks=)r~pRzm}D`}Ya5MhCg33%Z*Solrd zXxiW)NHVQV#--a(U;3jg+~WCeX1-d1rMdHK1muEtykO*G-h-O*>KSJP9m@Oahn=Gi8FJ2o9)Qk++>bQYa(>1|(yVsAaI${ngoU&A1&J!tdeWw{1g{T^ADcibOA<`PxFt?$ z@1jd}rgX87)_28u8#)nZ-n9N5ZS6izVcUs3T6vpN@>x22@|`m1(M!sq8OlDR;8Zu| zCyBAU;gwd8)2vJbjGL z?w+GO+aYmEc}dFfkf&}+$m?w01yaKQEsVs&0p$QquBb;&6!YpElU?#QH+z_j3i1x8cuCfF<0Y+! z5l1I33F@_-Y?BT`=>Vzp64tv`cYNAkn>OjSY1jX-&80qzBroJk{6F(@DTq|F{hvpX zZt*|=t^=~~n7WKzkW^7IW!uJ@H6Ua@^pf(EO0xZZXFrAn9th-h_x~6o)p&Oos6xl0 zoulv2UyOZySc;qvLDV56gWjNCLjU6>1#MFuOx|0^I_Asn`Q$pQmdL^`Ygo-mte!Od0kOj&hvL86g2U|F*cF2)Es5*$O)asV@`7U1!fm~&yh zJp?@nao3Xw%7c~Zu(JnuHL}lobnIf)E|{Rq_scR~A&>3(O&*E!h)&O;OgzsEqV&*F zj8)~SIru;ToX1H;v@|#%;Nqfy#3@x|;s@!fQkv0{OB0Oq&j7;A^dJN+#CIHfIgiXA z_!9Q;I6x0$6p2C1xMyvcWZT)Xc}$V5@!05<^+01RSCYI?wUO>sFx~>4uxd-Yp4`+* zCwD`+sc9^?;Akeg4mR6jvZ%mEW+>#!11D#kF(ZOmF7`s`Pq~4c8YSqrzu?egTRG1q?ue6B`vYgdCss82o5lpu7)O zgce$@*y(yf;;KVzDxcFepO-vkwax)Z%T2yA{0ouGAI>aT5ETR$aCl9M)GU8+eX@i;VKX&(kHsy0^ zBa?a>LD2TZv}JrFT~Ca&YDQV6E0GaxIt5D8kdU+zyIqEx<6b?}E3rdugp99>5oNv^ zZ`A_en6ffU?FyhZcDn*-#!gEzWNB55C`(Ovu9BS2-Z%XK7M2$#ljcfgI8HLS33OL1 z&@P_xifSAZot-&z%1+dHyD6Y;Z1H`5zjqx|zYng1*n*vU1Z#GtNg}5_()UcG#{(o9V0HL0M%gS07)55M+udrAQzOR3iPA&`3&(LnCvjpEzU& zlHIfK(PGA)RhIxEuuzm-vTNUm8_z@y84VJv_rij11$9PtZ)Gqy54m*yObW0vE1NGg z@w2GqmFGzl#tSLSALdvcjg@tcsBCsAD%O=k0{)aq3c#Epb<8Dr=r25w#Z4cMt5C`5 z6yAemOOloO1E&{kceqe+bBxY4SsQ4Lg9fS%hpXXab|$Wd2%*96qivIzO$Anq;vR~% zt0AoAe-CoK7S1)G*m6y}!)i5>?wX!0`3;aO^GyzbPO@5foOxf(8*A>XdGDWkU=0k_ z-x@f_r)GEw#A*rM!`0r^5Z3a)8&dz7)glm~Yhu}4XSH}xzpEpG7yGRrV*JK%1B6|* z2_lvo{MqZ-1C4_OC_}A;ik)k>cEH0CpI}wfP}I=XMb|foCTQSdyvRvW2<$I{j8!AY zLv{y*BEdx?^V9)?XOOud_0j{JpjioC? zwy`hTS7Vn+LGZu61=5CI|hH*dXhbIGn6m0i4BRi&2!_~D~j zEcFXb+EpHOkl;o*Wcf}*tL4~bBh?l$tX!zeBw(eW?Hn06>trRAY2h-faMD7#jotLm zp63@z6Np$|J4gi+mnwzU48urvg4&9ExHF7M><8hzMk2o?fO&tu31X915-5Q6&}cVT z7^DiN9#k2%H&~FUMPK84>n4mU!s1&r3O6}ur?!XLp{_(`V&u%NY zc561_9yIAtvfF;o7JW4E64=ieSNfWq)7F~>YA8)XtJ<3HQ(=BQu|B4ixyX8)D(TX) zDEx81eao`1ik$tj_YZyFJ5lXeI@YE-7L~692H`1QbR?>`hoaS7Hx@hE;4>4~fF|yo zt{>wLiIZ_C#*&4I*JW^|Q;P#>t7N451@bCcNbBqRWBOwNtdE;Gb-IiePONA!&Hu zisB&FJXd<8O?RaqN}=V#XcRAlw_F_*F_vf(dSEmWnCzRXT}*^@b_(q^^40w#$y_1w zuvXN{$F_zBy>b*pgIWtXvf4Hte*r^MC5)pPhVacGvHg%E-rJBw5cUtW^aMLa>*YNN zQ3&5|nnyn?H{M4zIqUR`d0kh1=3XUhedE_Hta-jP+3ZsDVdL^18$mTn^GL38{={p#DK{DN)(HlGy?@Fa%2OY;v_<^xz`I`$CbG6(Jn;OW9+JRDiVsm6e#gJ3*! zxxz;!S+#lJD887bKRAQC%yFHPlorQl9oChnP@4!1N5Zy)gn-43bTG$wJa-0IVslkp zf28{0tWOpntK2q{DwWh9hx2f~hTO(1kRh9z8Z16LAP6rPz$Ox3xB^MuQ~Q<^T4jBi zRcI8dlokD19l=RQEBF+N{`t!MESI+(Z+AgEtIR1MnY&(&Eda_`RzmHlIEw$&oa3?x z&f>ww;e@9O=Nxn^TuJelXdaoT1I--!Xt0P3XRG4oAc&*i*rMak(2xe!aoZ2nXrH4h z)dihufC_jJntytthwJNi|L~?GKv_CaQR6NWSr6k{UGMbQ_wjmgKU>f)5v?rBGxtj^^9#AWn>P_pqU&l$se@ zba+-rm{-F^Cs-5bPF(C5lJg6TiMv(uRi27A>bzJh(S83S?i*xVk!YI%S*?*HLUj=E z6mzJEqo&=oSlil)NkN)pO>1wvPk?Y*d_f22R6e2d2!}T zO~>0ovnn(llI#S0wHyW}bno z&4=tZg<+F#<7El?<>^d>$(YYEmj`&WbSOQJfBt^LOjst^&JQWJ_2Nl$j4jZfXQT7C z4Q7CBk;c(lgh)k-7M{Kfw(!XmVvtHheZ{5N>=zYdvlmm-D5N1blLby!Opd1X8`4Pv z81u-4NXBz*+km)aC+2Yg10uSUpe|l<7w)aYsVxX_^9%GLqiBXDamBmyAdO+eU8|df zLUYB-H;51!rpRAyvnqF}GL5$F*#PvO=yquBvWNl5mes3KMa!%wY|t+V1<}k$hVGj{ zSR<+HU~*@D3Trd68=sHRBJCS@aYR0`V=hUVEK%z$XZB4%5?A@gZj9~P9yjkeuzRZw z=ic#UzA-d!CqPp%En5|l_Cseg&|Vm(O~o~1lg4)zLaoHoU|_HeF##V5eVahnNQrGw z@zMC0vypn&ge9(qvCnQ+S94~&2yT)QyM40>-s-}!KO0Hxwz`iYXv?v)AZ0mFH)xvl9zLC@E|s zMRZ&#W2}tITh*?yN6b8q&VCu*m|Q`Af$S)a#nIB#yt{AKLZQaP5r_Si$r5hi@m#6} zoR|2RfEO^CE~3S(8r7nqHxo%4uY)*dFt`6qf_gGUhYcM_zD>okZ6ve7A=$1Cl|&l4 z8l|_QIhu{$b_&?sJYB<5F_%A=lLC&+q;}MUVI2&+u^=0!v7+f)fhaIQ2 zPZEnoaV$id#)y7z4$lP4QK6XQ`SLxeLM-pXtwS5B)0!??3Arcz{qk@GVM!QTip7MQ zVZ`&HvxqBzWB$HXre}peqx)CswqeGWlOr^Xd?sZND=<8tSP8eCWvR>ookn`!D{tY8 zl1Um_qyUNbZf23;;(ZKJ@aT+o4CQnyQM+j`*a~HwpF`Ze2q6ol!15id2G1s0&!!Ai*8Ifgsm|S2bR%9G-bi*a9ruZ+q|tIRQ*kJ zRk!bC)k&s`-Uz~;a`1x6L%LE4Dh@mw1Q4>xG0eMt;g3$0a8}4rENb2_WawaPdUc?R zBSxpO8y_b-s%SD4S;19!34c{3sa8d1hl}Sy7)mn>@kt%vf-klw+8vI<^*&)Uf|i82 zamGj0W#1E@l3ioGlb+1n{*GL5_guOK>sSxypOgs$}@V&D}?_o1F?9pn|vEs2f~p-N8D+4Lfs* zGo7O)lQ0!Jb=tf#$u}m<%}~X9Dlvli0%XCZr%r~(q@kAX3+Zwb_u4^PHEee0C?qpz z+DbjJ>8(wxDIU5&X`#wD<}{Vy?K8%laG8~!K(qqqIWl-)oM;7)_6{2&*eWIuanQ1Q zkB^489!Bx_W&M_EWc<)rY{OK$z{rLrTD^;k;z&EqW?_0AZIDAd#0aX{f-2E2>If+D zMJv{iR`ch)K}%xTS;6T?X!A^g(un~Pw_U|&N%MX@brx$(XLMH>AgsHL_GC1y))*n} z{IEqAY(S!M)y;b$IU%LF-L-2($;Jv5moxzp2nv4NK_bF&JtFp}QlH1`Qv_;uBlG5W z%=Y33yaZ?#=2^m+B5AG!@53yhRbh23y~f{rF+5U$mj{sZWdH}2zV`(?2m+diz}wpp z%G(~|dR7&a*zw9~e0>L2oyJpvA@w7_O=J}`(wIfHK|Kp=)kl-K!Lzd13(*||O-aXy zn2|?^VOB#Vkxj_fZxb4b!7_-pw^W1hRCUc-rG4`cqz%c~swr&bfz|;LF4iXr+^kFz zP~#Y|W2KOJfF-qpTjVRy+bEFIG@8{wNg^#hkVdt6M?O;v6ou~~z|J%M=q38R^}_}-Y@-hy6Og}?3&4%^v+gydHu!CSCe0l_Ca zMT!=iJyu%f%^*5++JX~vmAeHKHt^4470qlaF7P6rAWS-2TEpSs6lXoy(9{|u6223> zWB~D9)F`wDWp-^MtM~&w-kVp?2b^e_R=2eADEP9ZF=Qs=cGbnBcvX+i1YB{&;AlSi zf`G|_cfcu&1tpmcYn4M-qtv!ktf@oogd?iHomA{9FFU$yYo$>hp&E~}7xvB}_Uz3< zsYjZ(6gKa-^rG3I`)Nl8s7Z>7(p}As^bwHolV9Xqd2Pt zu;$bZYsyBmcQk%koVLBi;tF>3(n_#fFVyfEgTN8|pc9~TJXpg{xf&`dvldx(Wz9f?G*iVDR`ZqPwo{oC9W2^62^Goq z<3w?rEe+Jj>+x{woMG}fZa%?)s zCx2QAV@eXjC4zJCv-nL(nL3GQ?Y9YM1(03P$8ijA?1Hi4atjYAXM_ygTaw z^lG(8-uH?ZQ_u>n9Hsn(0+t)tAHq%nK1C|eDhO%onMm!Xx2@v2M8pS*bn<3m7=i-T7b(M=;Qd5attU(kq2I#uF|5hgWMU;dFQa~ZRhFG+M(aBayJWx zrA2IKQA?pj2`fqQRuekCgMzXlLMo#KBY95cdnd@RMAW(2kwNmdpT`iATWwIqZlW=Qt#n(Xroh1oC+ZI4vTp%%BeGIhP_h`KRUC*0_ZoZst9Ou42IBom9>n5m0v(IDL3y-<>)7@% z51p_ykY^owB**p^f3(9V53^Sh2aq0?jf3m}7#Z>o*e0%L9Z7gNY&4PpcNht6Lc7ItCE>SejA2hOw+71yR zOh9LIWfc2HkBsg&#Uq_TeB))sbTesVH0lT5x=`Y~m}>G>kA$50P2b=%fZ?D0J_BQ9 zN3`cd-rh<|ycN3vr^mhhplB6S^AOMj>SKuQ7>NVVTJ+}O9oVkMu8qEq9m8hFa+=u> zV4D@%g+J;qtL>m7ko1mK1x&h3mQhCX$&d-T40jF4j5-a#!b)AoE1(n^Jv@c?z0m{t z%(p#fh_9$)UBhD>Dlx6dLp!s;O)R|6UUo*00T~?+DpbF5hMK@EfCXw-3%jv>yxPr% z2v>^i_IjH4xJTQ@I8NarH+{nM_Gsq30ScT5yL)tEIB|yK!3n^h1(uE;djNS;H1rF2 z`2tf0T+f-5ADb$*Y^E6WJ>L&qdhFERlVSr0Kcq|>JVPrEZuCE0b{^bl4M*^jI!n*T zq58m{$uV4Bq37Y%LNhxgaX>KZHul2Nz(R;+q)u{;)O8nL{p6NbROCZb*g!2i7#1@* zI$Oqa5&Y;5_Jk)%YeiBuLc0mfPiFC!FQ;>U9%rn@Mh3o*%w4tP{t_tpMNe9hA0ePx zT>AKxhaSU9FCQ*29F~bjd|{i-#7q=-tbg%U6QDr}L1m@T5(7Y{zm^F}Cf`&+& z?x{|l{)+o1sIg+hGR9h)i5 zRVQg_v9=gx8hi1fl3N>(xlM4@jOu?cVdph ziRznkK}9M{60kj!HVH@Aq)XeeeKSkqS^>OD^Uuf^)U&vGJCg}}k0QsKywE<};L@SS1)6|Q|zWcxFxsj#wbl7 zv^8!!$e=MKk1g%T4s%@d6NhdACbn%tiHOVqL`g|+pfVFiSdfU~*nKC3<|05N+yG)e zJz@Y6D=1?EjA+fU1yAAF45s^#NMYL4AA`k16%Oj5<8%9%(?uMvd}>@SBgG1ezD7sv zrn)Q?B{9m{stQ^c6tk{4!w`@FsGKrC#x1=ZM0w;sfFat4Clmw7F!h#40HOVRrAvU6 zLz01uwdVsk1P6__>I8S+!PchLN8Q8(ylccIy^`pN&mv14^x>dSF5m~wCZ}ePk+-be z&?t*GG|Hx!On#G_x2@x*OB~RtE?5{OgE2z(hnO5g03d?+WwU1Dw2%9*7x(}<2%U_H zN0hCI1MP}7(9<5VZ#sc&1FHE&jyZ`c0%H#B#S%Jg@=Y7}B5Ce~(xMw87#d~<+L1u#~gH4a%{hA3_>hUK;kbInxkYt6^(C6=JQ!Y6KqD{>)`;P$#R99konHCcd3 zUwCN)aw85}nGi}l7z&>jp%qcgpP9oBcB|`*CK+m3dA9QMh^@S=rDS6ot1>b2K4_F= zx5^DC64lGSB8ZqqeFT`o9o`A@Txxv~$mvx{C}R|dZcSn*PwdAcyEf@0FFJd!7GBno zjwW%a2`4Vw4#gLFL>|X+Iaqs%BVo;vBu*YTgnNlXfVMc6>jcjPPSCDo#FS;D>d*GW zs`kSOYMD0)&F9`bEc@Q!PqTSfv}sPc@~1KnPo2bz*Jo5MO(1F^PGgR`fNOkaKC@T> zR(y^t0cvsBZ!6K3onU7!n|CptA;AFw)n?P^0AL6_6*6^d@f1!*m!KCh%9>#)7_FMp zANH{sh?zLK3m4SxobI=KASrO+Fc-J>hjIS_?8~f-Cty}Jr=Lw=uDY7q7D{`Lm ze8TWO#Oc60!Dmi0Vdg>x9e#eQ`~U2I^2gm>e?0TM%LAAG;6J&}VlJ2Og3-T`)(#qd z>xwS7zSx<|<41mj3HiQXT;19l87f@cZk3rBFWrI8VP05nHI=u>mOf0AYQxBM+PR_(4Lz9qW+^5JC#_ zKmz*55Hs@haiigTilg?I{k8uoG8#`Kfm|0UK-wKLU7_(O`Tz1SK7a46BbOh}pZoL| zzuN!Zo=V;c7JYIyZE;JBHuSxWn#??oM~Webya!W9}~e-|6olIG@#i$o)7U}d_h@{L#vjo5H5&h# z#%(mlXncXjKc?~TX#86m&(Zip81+vLb<~zUw+tMA2x4Z~8G?fy<#x|dZYiGPE6CGR zC$|*u?hWWdtcqayHoV>qd#-2~zQarkN5*mHTIl6}Tj+47~m3EYO?A*F% z`$%PY_nw<`$2&H04Gu9SXY_OLYucV3%GGMCm0g=BIp5WCy9woXBUO2P^~K+Bm#aPd zejx29I*xbTa10weAWTpP-;&ZNhjL$Ctqjw)2!SqHT7OrIu#h|6*GUcD1|FZ%9=X~d zp#a|({o>;Yz>n4g_Kz_~pXUnt0p9&{8BXO++7>K}T)&|7;ncl^YvHM)|c@Kv~X zwMM)2c54j`uJ+CMOTl~uwf4al3+-5a&eeYB{m@@O2nzcTgxd$h>wLM6?)+BayNgHi9LaSM$B8bumgXpGRdVQ zn;qSK_%`x1CTYykSfIg#8(-_}E;JsYjfpf~q`{DlH)*^D-=(9lEs5yYX?u*Y7ic5i z67iOqk!41|e3nLy#xe~Oy?maMdttg0a_cm#g|Bqvi|Y!tdY|O@LhTp&Am$co4;Q`y z8J2K4>xDydJ}T!Sz)j?R+&)isQ4BuBNY66TBIgQ)q9p#>w+-i8O1Q|>ihYGG9UHu* zu*GbHfZZS%Z1`iS!9o$CItoQf>PWhS5XPMsC@)Z7q4r&R;rl(ru5aHBn6nVjhgPtz z=z2gPY>X2hQd|2TsO_I4QT=m9;s0Xj!lA+zOblFM3ynjP+i&Tn^j;Y5Ep`^_U9c4D z8~pU33lS8yD7#ybT@>w>e6gdjg=sTivS@~cEWsaMmJNl;6PpxoVJVPeSUP$LvO-Wc z%-XTBn8zdvKZE#1QFYTLJMyF0k*f=;iAPA)UQxBTkM!(i#67fFWTJF03EZnRdyq4; zsSft~*Oel$bVXw-s-mh4X!W>}rVS=<}0C;fpkHa~T?;qz}2*rfT zLiu$J^bz6)F*`zCv()?VM{^rQ9e}nDeHoMxW`m#paUg?c#MGCE7jcPSx+wKaTMpg$_0Rgun z1Rpu>Gsk_xebjItrK9#WbNqsRHVgJdo=HA2SU7t_u>%~?k^@k7&Y=s_{rBe`$bGy} zN3YIxz{w2N9v@^4!1ClEnlmaexSt;ELtS-PRK4s$waehYNaIGdXmb>5=apvS>3hT> zHgyyrXc*lx5!xVcdOePs1}eR9{op13zMMB*~v#l-#L;s*59 zLj4a5_5V<)|Hnf8KNsqM(qI46LjBJ_Qq05STP^)q=eud#M&t7;5Gxi{d!e>0%4?6I zM-3SNKHJZBfg&}Z%a%!2NLn?h4P>xzXm9|ftuMS){AbxF*`V=3pI}$c6^3OVw+L(Y zc?1yvudfdks4qrg78)wWw_}!Thd}kO8%QO~(MCn<{T96+%UB?2f@&K*pRLtGzdNfg zc9t!#aMm*iSH4{2hP!z-%#x8$@dI)<@0c^3(j?U z=DffDs(oIg=SCF7r))jQ7? zYTraKn9@+?6Q?@wAmJKaFl3_IR6S?O%)l?ctK@7bMWMZv6xvHHG@)vgBFE$SjDa`| zK>fWCsrXl14-ki>06}j1d)amjRfE$2iO4}XzdUzZesZs zrZIk@(!rtXpYLWHuf0Ol+Bu=t&MDkp3&&9^C(a87go<+gj3Y-AS$%^@_{ecd=354O zOOZTgk)T@v`AwOZRm_+BH!-dOvC+36Z_4lc7WVs)GawEiCkFlwGg;qcnZ(z6m>MeT z{+6&=$wH#Ml?Q-F=D+#2*3c4 z&&vS7GH507atMQ9tS3ZsPMC5#3@@qs`QULOSS|+3E5ULpSS|<4m0-CVEN^y`f^!}A zv9|TR>g9sWi!#-A>a2Xo=`yd#yejie(fxdXoqtC6^C2q)DXrLY4ymCS5)aD*Ff0$S zSRP=pJiuakfW`6vi{$|p%fs_s%ER-P2W#h;iGY7Wp6$r>bagrOju%LAgUklp7lZ+l z)CcVOVrP#Soig?uoH_4AU9UslP*`uW%GV*{br$hDMf{?2`DUR`3ryfyWMGpPjqyuF z@G9vc^IXT3f(?*OxnPh7vsv$L8&j+JV*OQ>=Xp${`Wv@f5uXo5OsEonHCO<7QxI5Q zRjHiE*t0&@)zzVdkSkaR$)7>aYsg9ts~B$3(t1rnFJP*s6llR;k6UM!Jcm6r%?OeY zq!2NLwx;`91hLu$j@2A2R&y6NhA`G5;9>O-i`73YR{yYA{loH_a(1D|K7AY52LZmY zF|p+p?Ms6!fco=c8SQcS1Dq%4yVKFLUF)CrX zD)KH`7U8~VZpd4lw{-P4KC!XboD!+^!;f#rG8^GdgU`jj*(lz&Fe zr9cfqq9(Q&HGq(ae1u_X!^6^s#nOhw(uU>v5Zx%k3S>gav*{rg^Ddk z1Rz!y(kD}fqKfyJ@{i;)G3kp+v91&fh!wKqg>{qd^$9~#62Hh~5Hhp@VF7TxVV>oz3Ly{{iFq5mdjdEFhivNO#FV))h7v9` zYN!%^@JIQPZvT~{pi%4dZpoEG0G%j<8tKkkFn!@#I% zk1F94{f(bvNPJiT_}G*UwV)u4FQCZ`cA?-oF@aRsc)?~AjTca!C~<*cg%T6dnh7LP zvutS}QhN6r=zcnuZj)o_HaVP3jubgWq)&Z;uzDAZwvOQh(l3hEZ2g;9@b#{K<*)G^ zF&l3yHx~h>rS>!|#9H3mzX`MRn+uJKIZ*C56mxRtVOQ9Ts>qA|n|g}QFdG+pJyM|o zcoG902(>ZtOyfflpw4{^wWkxL+SBk*t{NARUjNdYbl{`JFF@%8(nisu>Zd8hq7t72 z0!+y1XpyK*W@)(>e~M+_5%i@-W3LDt^ATzOo&lehtT@KaXhg5P#q*Za_j79bpw%W7O z5`pvs$Z;=dF**v3XGKIECN$v;fR7xf&2d_e7tQe^k?Y?RXwE?T6dE^UV$;#LDdc~V zh>b;}Seb$3O>!;Wf)8fH-`@n)!tyk98@2DFcniy&0?b7K(p`InqU*Yj{HFY-Ff(4B zR!qxGy1(&czHc~Z&FG_!4X1lJmxGO-5JvPlXP@W!p&+i$iv~Pzp9}W6XrGtu^NM{i zI5V=#_PJu8tM+-5AMiVUAobH#ds2Rl+s*ZK9<#ZQ{!P8UwRe!p(9}C%C+kNsNs9{0 zG}=l>A1W0SNkxt_FwXJ{VnVrIVt)r)y^^riE9{5lr&yf8N(I&_R7aXZdHY*p5?Ec) zK*MjL*h7{+jzMQ{M^_gVx&t>CHzpuKsLjG~23|r$l7oWa5Cx|>_+ck!^k8~#n^Ti( zG*9dNZ^I&1{5GROeZs8>p;Zr7W2$dc9gRj){}_50nJMD~Z$&)ft#7MHmq-1F1o=cs zgwe1(s;r{t@;gvi>I~(ygjItL1AXk)X}j}Cy$Mn;kv#OK1bP#p9NU(PHtZ?KeTAiA zC6Dz*$RcnR0z$dH_X)T~ud@gM_TyHs>+)!v+1Ra`e;k z9QDm?X;jT@>5wmj<4GAv`%Y*d7QCz-;cM*(mb4wkAm5Ix5dllG!_s4<60s=dN#A;w zCe7(v&(fswI$2nn6#JWGvTQv|vgO%&yj86ScGMf2jUocWLlo@hOnY5|Jkf5unyGliu$R7=k=2Y}1*9hq+!$oww~^sFlQ*-*jX6!4o?!B5EX zg!24EsAeDSOUn8isAh|kSV)a?0(`!&Fwcbwd(JBCoX^&aNw!{0GSI(t)mPZnP+?bB zR+vE93cKnn>?%`6EK2!esIZIX3>9`!R9`GCT~vi#M1@^dg~?_WW>%}Pi%EqsB2*Y6 zP=$#PqrwPAejx{_Ctpf(b}8fx{X5}c z2QNc!p*|uhurp89CV}7+LCZ-jN|0wEO4dIQhsE>~VOxm)J!nY#To+cf`hpWEg{8n3 zm){Q_7s#`W;mao;$5Q1LP)-o(cT3>lsik8#UwA@LWmOBGYz*Ak|yU}5+#ve5Kh+hQI z*90oHz2(h`e6_qekPQP{GgPKFpLqTPg3-3aXcD{UH zVfm)@W;p}~13+J=(>?%n1j%uAaS?2(P?IrI8{ZYFjaNAmEI%vrd76#atZgoT0|C7ikBgt z=jDdb=D#m`|MUKP!GFaefd8_0zv91_{1?jxqU(zPUiIHM^@RXu?#At`j^!H51RptG zG6&XSFwKSh(gB%m0kva7QCHWETz>%^YEStD0jsBvt1uLJ4BqeYpe=@e<|TCL4;6b2 zA%PfXFST|ID7@l^)M5TT-XF5rChrSt@B?2!SVXTq3uf&Li398rF<;PT3~YNrm+FAg z#f7dx=m%k6M}_p@y1{j5w2-4IO49;;!#P==r;Y*bqW%H}YFaSXyeO~p)H)FP0<{jb zT%^{4mY4A-3$$;q$a0BV2YOwmfK3b3Jy&Fbf(2t1AW%O*-;KTlVG(Qx5NM-crKRyC zCjf*%)kIzM#*K2l4zUQX?rs=8+zQ{@EA-nj8(Z(dKfXb^h&@z2qR`M_Ev-fW@_DQ8 zWmW!i=Vt8BS-08sb-{w2H89V1ZPv~jngZ9p4TKK-_W+68T7ZOYEwIl4IDr2=!)>8) zh=H-^geC)H)ko+TXx1Mg9Gf|4!WYu(mi3!$<3=Z3`EEG4djs}9+PQB7aSSl6`)M3z zP;7c21y2z`Tx&48^+njRfJn$* zA`(!*`XJ3qGT)NtWAq#l;QJ`vE&&;9q4phQxQpeDb_`ojR~`|+Km;t!5aDt9t%D!d zSm^hn0>4VAvQ>W#F>Vy_b=bP`ub82fBV8{s5Sj|2YAiEnQ25XTS{8zs5*V?}Lo!*) z1t?T#I+-M#S_a}@Ky=g*X!5q<+G0WDc4|Uali#*Ws zd7OjcdI{YGE5=dbVU|erQHxyVhM|wBoy;-@JDShaY`n&BVE8m&LS?8YHx`Jkx&~X2 z-*P_Z^4MGI94sBObme&1TMo3dd@GFx#J!zJ?FYAGoLtd%(>p2Tkp5zJ9kgcjm4=jDQv3dj!#?+ zgNrqyP5O5XH~)-e0nXLGm~-`?3lZw9SvG=g7Gz|%LhcC>>>S=^QJMdaZ9BG)Y~8*U zFvFmY|GUPwPLy`+Dvy*Z<9jBCOWU_qc8`=w!xN>-#Q5-dWlv@I#Q4rqrM!D$_pXVP z!`pZ5+*#heeWbi+&z@~tD<`*YKUvwer!>B2e8+gXymfpW_HEmDZr#3Z>+rTc!^0+#J_#paAnW7N@;jUrCb@Q?B2Gu zJY3p=3)go~Y~4AsqdZa`F7Mf1-dZ||BzNx^-??pDxm4P@V;hp2D2?yjKE7)N(1~s1 zl^qjXcU5*&N)y9KYY%+3?c7@4UD~>BWc$t?TX%08-Z@?#-m`uC$jJB((76YvN9vzP z0pIHj_;VGUvPjNQpnCqHbpLLp`%!jTY{~xId}$8nH>(&3qbMBw16P>AsD-O|(l0yo`$x^j=vQn7=KfvK@T+>z=A1W3n7Z&C|^~p~@ zFgtWAc}S%^d+L)DU!Ix6+Ox>o@8jh7=3}_FeCB~-a@?QCMYa^}&bgxQD_@Ov zfA(A#MO{l&@30csN`4EJKBnWxX%(;8LYnc@pzmJmxB$Zbe2s+u?k!`D1m2Z){v>kp zt9oNBIUl!n3FD6Rv{W~z)_1Rf{~O5qvnH~d(s>uk_lKX4N0EeD&*sir&jisfmH2E{MqCS(krMZ0Ncyf}sNqByZg2^TPoAJxi`b05gLKAeQ}H_VYK zJ9k^o{aBDnQF*usF8ITS+ZJ))%DD|VBF)=JocmzT_2Wj5%p(Bf5WWg1bKvNvD) zGDf8#Ps<5iB^DCT;-tx5`w88qRBc9Lm!DWk*Vm(rex+3|GiAgsWWfS$t%9T!{{1VM zdLIhn*IVT(QxH}NKLQPf7%g9^m!mcF))klY3obk0Qrmivjb}bnAMpq_5`Ozwj~yRs-gur$O4jL%pSF0a7{p z+GheyclAIb0q3jzPWwg@4FIeTj4^zG;zxkh)gk)Uo?NqFTHSemy|&e#&$$!fro2Qq zUTveherL+@+G8l~U)D>mUbIObJ$?sjgyK=D6N-3#!S|8OtgUtQ&_@IzUhI!+c2G!M zBcE!%8~=K(`x~)_2?6Q8s-9ix75Y_e~&C{{Cx zGcIn)2CEl07Pa2PhIT{Fb&vARN31{Gn{%Iu84B0$hG-xM{z_43E{T39Q1lFg#2GSOUT6>|0<=H6C-fZ7Gwudbp6P2-t0uBtqZ$E$M*U&d@a{2$YwT2s+@cP~)P7L_6 zbq+g}Z#7x6m_962^tyCg!%cf@Q4i)p6SS0b|1t#&+D6wZ-Wb}gZMedFF?fwryN7?W zoNxkcxT;nbezJ&nhqz0(h?o1YdH2huGgb2ueu^IUR4MA{xl4Cz&fVlm6PV3s9-C+F z0EG7`hKKSTS62b#BXvdZi8kjmZjY%Zhahatn!{7kda-kdbM9bh9)L@+Ha&#`UPZ+g zv}6_s5)J#sxO(m@!8uOk{4SCpN=c~mlD%5#jduEc#o}k6q^o;$M6<4PI(dp zb#?^eX_cUv-G`U|9;zhIGU2oela=qW#gj99!N_uNx%Lky6~kjn?(UpB^p10#eSRs* zGIg#;OXUYE3!ZvuZ~XRgJAs3JkX1ZBl@tfh$ILplCT4N}^lbS-upppK%|flrnk8IZ ziP3+ylJGanYxDqO(LVv?+)w1(N98f6*YiBVV@FX?cr=d8(YcT0+z0iXfW7K`C-xrN z(-tUo79xjdzlsnZ&@g(igMYp_HfnWa4(ws%o0qob@pH5D55mn3f#>=8MEGG@=-CYb_W6cjQxQF4(s|u6HIj`4>s6$Yw{dTM7 zWlL)-izJLg*SGw{eN+@-yoAJ!F-Hy`D30z2x0-)w3eu5tKa+C@Vul&1J<)z!D+i}5 zqbEZQNhAN;M-|lJQB=EgZhIT5lA}{YdZXB$y-!BYnVg#n@fGL%qi1a-l5lbf=Vgjm zQJI{5=jWx?T7Z|L)o)KQed~{WXIxn%*;aPFGASsA_^z7vJ+2$AV!+0re&W_lD~DQI zDqs%PHwYQZsuRi5Kjq51r!=MU8aRqevuN}DS)rrysJ2Zo#@vEPGs+VV)KDjTneXtd z&9^MtZfF9r)d1%lPJB2f7QJ->GqZ&wb14Z>^_=)L08;VJU@c3rY1DDFeg&L(hwy*j-gWMov{}KJx z5>W^qAQIfj)(9+4ai)QMp1DSpJh%OLheU_TXkjSWe!+rUe}^&r@JAF=U&7! zkC@W%BcOj5{bECGi#9;VMyXMX4LErHrJH*2MPue%lD40ob#mnsiyY9P#n6W=U5lC%RZ;YuD8zS`ik8 z5YH@XV-b`rM7fLWDzpQ(t|D^8HunHRlwei>v6jiU$hI-><64A`bbLzXpG~K^7TVRp uZd|UB!;7O;{IbpQ1$DJeh~4!cetzUi;Qs-Y^Rin2 diff --git a/csharp/ql/test/resources/assemblies/System.Web.ApplicationServices.dll b/csharp/ql/test/resources/assemblies/System.Web.ApplicationServices.dll deleted file mode 100644 index 85db5a3a7e4fe011cddeafc11f79a488f966ea34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13824 zcmeHNdz2hymA_Th-P7~vo@59yzyvA;Nq{i+%=El~kW6MKVPJ-Yc?B?%)O1(R^rok} zsqRiPAktZo$H^)P7~qHsvaYhLEJRR2S>u8Ok;S72%mLlQqM)+s;ywV^MPPsT)}w2Z zfcpo>v)I?|%1tR8S|GgY_{{?LUyeILA?HJ*wI5|w{;ytL z$RZrSK9^`CGuw!6^Np~;Jt{;EV80K&W>5Bix$3^_q8$Z3Cvaa&$=p=}?mrC#WztsH zZy-5zc-3MT?G%vswhc@KXA922u@>FcVw<@<6xmm*;AC4#oPlF4(YgQ>R_D0lVBb^< zQ(+m=3oD6gMOr1B(Edslz9VlA|1b?`}`Ip;HV6oT` zsJm6lRm7fd00h{8IY;rGC_M0N`YP;=7;qTRNn8;-*Q-EXU{Q3UTeNQU+;s{m5m9vPzR^!^6^nhfala+zF~Z@ zAJ?_Och&%}%jGA5`9K;do3}ooNq_#2(oTyZfV>@N9OojOJ8)KTLYLqtp;|i0#jMLG z55tpjwz`;QtWWezlzC3fMKx3#p_fCu8tSPg#*%@Whavf0gy|_l9}P3VPUu#l2SmO= z__@&Q4H5cinCVrKgP<>jnVwq1^b(=J4}A^%lQm2)i7>r8GS?WP^--p!IMWRx`McV3 zEJ9xhGrc9m@)csOrk4F2u4DRm-N!+-My5ZFlw)5D4UgY`^zi2PY%J|m@@>zIF9bk1#H{<#=a13I3y=j)~+ zv54u#pq^Zz93(N&O*#kenk9C_V#Mb{L01D6RE4(rWer#ZrhPQ4hN$49iW;F^4vOBU zT%*>|<$~tcuAu_Z6~5+T%!VHoTKVvrs%I=$o{-q{Z*4!9GXT)y}+}BXMCxAi?!5VIo z`aZ97_18o-NE!x$vv>IhE%IKIXzN)!(D??7_!e_|p3O)g^R~&gd~E zrR-OQ1)2+gxc+f<8GT6vk10izEvLWt(NikVHGIs4ABi4Rd6wa0F8r2yP(9TFKz|*3 zL2dET8QRS%&qaL9g$I>?4WRq$f1~pJ#>ZUv{`%L|4hI1JZS+mGi}vX(cuYwus@Cn7 zjl+se!;s8{udR=2XZmHC`j~c>k1nb|N?T12=qzw@a1DLaLDAnvkI~l9w*<}61f8I* zrEfcBw7>3Tt(P7Z#JRMX`shig45&rxqo)PU)!rB1qi&*uF8XG?0VDQV7yVKj)GnYO zyJ#}HN4}2;8KIxK=oiSkQF_@$y2j{NE?N~D)JEwQ z7xjiV0{y#-q9_}q|8mjS;ma7k?xOE%8-f1YMOUM2oZfKJRNWqRoZfQL7cm~jF(VO< zx!RG&3225~G$&;>4pLsFqfl1oqL=DFr*5X0iw2cF>czCcM{fch<)U$veUKLW=uMzw z97H$O>`}K+vs-p;{S81T2y%LJ3#}0J^V;vnZ${avF1icx+(M^2n&|0^wJov=6aBpQ zNAU^mL)7k+q2FUb9WHvlZZTa#T`t;Rw@tf*dIbGkNjFSu+vqH}>@RB?uoXSqMSs({ zm<(ChiGHHoRksR=4^6Vp(s*acXikZ#CC&6vRJ~lA^3hw$b=r1XCpMj|<6Q_jL3!jMkb~ylOVLYl`M&~+_!05O~yPQTG6ir~x`Us7?=uGTDK0=#a)K+_+b|qcx zqQTk+fws8lA@p>Gwz}vWvxxHJIu&w-z95pIPLMxb|HIg=DHNn}jqSgTx-_~omH)Mup8i zQrErjAZJZgG&NV#vEL_m?UmBg(IU@Vhi7jUx>4F5)PD^dN`-z{*K&ue}v@}Y;1z$^VK(mhi8MK}zLj0_BC-@jOgP-3E z!5(q=mtjYBd&G$t_l4&61;<>G$SdNH*NULGPAh_v8F;1A1JW0#p>?VolPa%KJz5kZ z)>P;op^iTnV1KRB22h1|O5B*Lqz8EJH7D|(juUN1|8NT&e^v59qsJxM!8l~_4Do41 z@$)$C1_e(EHum1jKpW^3p{+uDg!T#@6ncTsi-a0NvqCQgT}ZRS?*?5=*9-jws6uyv z9!vL#mOwkNI&o_$1v9x|se$G#3hgiqK<(UMlo@ zp;2VVZ*VrytDp<$cc6>tEzl*TDN$;sD5y>`(37YMbS1qHbQLv&CQx@2kJ%@Ko+bQR z(eD?XA(3nXzk&~`<0uZgoK68fjW&R`3q6za;QNH0M^}O$75NA0 zi{MlA70~UpAGAmZKra`|SJ8?{3+#0{Z5P0F^Iqd zIu=w#G&Il{<|d3sP?Z`H9WJj0U5Myl9z(f`+-L+{1er=l1F3jmKN|FX_*0RSY&C)0 zQKWkNs0UP~Gmu#doe8QUGv5!onpS|Gjj^iG8c>ziBJWh{rPCo< z2dX0LJ^@M?IKlP=ktnWe?~Gtg6V#)u3arq+(Cf3k#E=Dp|0hV4u(j zz5p8vT?(p_4I3&lb`Z2g=Yj5^VYL3Mupg@M9OoRIL&J0%=2K6?@-rdhBPi>qS$U}e z@p`;&GOqzCaI$QAW>dVg*;QM4Ymo3er+f2%tQ$}j`oy%v;V$ql~(I069D!<*N zb>>voa{0jlt2|@c#$?W<5~99yqqQktC`+%8{O=N(u{gM^J4i>qu2Q2~XvsRj6 z(ZvW)5ZW+vJ`zvz09laBrqF`CB{EKiLuDL~O~{pO+O$Q96UPT!%I2lS?Rp>gmmTw_ zFDZMfzL)D}eQ;}B-K zAr%Bwd#UaDG7o2`?xB1YdpfFXmp-z=AG12a=GU$#?baR>vvJWr$F zoGedGvBm0LaA6`_%+8bb7K<2Px!JL7DX7Z5xIS<1G;B;V>+SqZ)rxn=dbDN&d4TX9 zUN~rF^7f3x-pC!MHH!A;&*cVZ3VFLU zY8rNGdXrI_4k$U9AhF@4WtVV)ax6J{%#d~|Yvj-|HpY^f?gNitS3U6j!^ldPQ>AJ_ zHDse^KD^ha!jte_hBaF)7%5vN%pxN9 zCg^IZtgJL5>kJi;uA^AqXe{r1vY^pfG<2qAvpLyvPQJ)%lT1K7KaJ&wjZ$iw%o!t_ z^S}|JEYs_7)*3M{EobfO@;GE#Q>AI@En->aNKP85?UeEu9_IrVj}>nP88I<7P53JY z`wT=OCu_FLy1gTPBZ($U(U7?VYGRH3lp6+wbEjwr`17*^S>N@yIBsPxEt`&fgR_G0 zJiTt#5e24iM_`KeK;Qz)$f#-W$YO42N#`7=1`%C1$XE!=GvcY&V)TK;XvCbt!e7AEQ{tXAOc2G~-y)a~F4 z$|e%m4Vq`t7X~&yzN}z48#-U$HnZwvu_e&X79PH1d72j~?iRQU(wD=8<3(y-s9U@h zn0UM5gKDdMQNfKLdf38xPE{3m7wC_YfgPq*I>)fmn3>2cMEfcM8h-T$$^0!{2KacLL4d?|PB#wbE{RaKs&6 z8t5fg-|Hh68cr=1<6E@bcyG~csV-4|Ss>qCZ=^n%eF78u`B>|7 z1w7C2hCQ1?PxJNxuF_~Zg~_f+{&F*B*y!k@W5L+vrikYp)XbRzin%=lyRt>F)l77f z)_ERrpGD@)mPk%)ZUQ%WX59kk8IkhxsEEPpY-V_~fHhex9lG9NH%o)Pygp%5hfNA$ z`sEAfD!Ow9Bh6WWTt4MqopLO@qREeqBl)}o28+CzHPai*CCUbPp6ZPm^gZvs_?IOq z_sX`shPd(BjK`Y%PFbu6F&pf{G{dylwvAabgvwp+oWXr|o;mA{M{kIDVt?g3w7{El zJViul#5B@)44L(khew7NNKfWtdEh7QyI*}_V#RBNd*4WX>)+0}Ri}`yC~6pFVT{>0 zlc=VXBC=tj9};TT=&I6GxhooB?aCw3uU)of;+W(M*GKPLv-Qe_Kdd{Wawq@JAygr{ z1+_)+`jhde}OXo^iwT*LOd$^cnSG^C5ldwu{c*``At9 z@z>q)?KO*z{?&tPzO=CQ-ukE8zw^qrWmBi$y5yIwU%dB`*qt>Wc>l9kJe)t!_~u0) zf96LWFAeql)j(g(%P*dJ^~sA?-+SP-y;tRLed4zpHvR0@E$N>w`Ru^+uWmo}w5APT ze$+hewMV1j58V^OD_jcUO*4feO!x&zD9nVN4e<+*5Z*gch~Jxp@XpqGMH0eWW2$_n zMX6lE1)Sj{TaAR|7U4+b}Zl zok^jvX`PN=X%W6<)VM=OT<5V#w0ny}yC7|(j;>59X|{HCwI;eVsm?@KS64FA2K()83A3loG!h+V%1oNwZLO(<(ShgB?o4ZE zvLlsDB~m@@sa9hWRd#ozJKNe)hSAy4hUzj#y0bmqm4r0YmNq*wtzBk^X=DEqqQyB-r3RG-InM~rxHEw?a5@i1Ag}4w;#uIo{XuBH`_)5`wM?lKgO>Diwe>R z2d9yAM&+}jKECU)*~ocfKhiVddpZpr_bv~g?CMGIkK1$Hp_AyKwZ5FoiGRw7Lc_s) z@}}*!L#J)`O;aG_+-W<}p6SSRWm;R)9mp92-%J$>$s;DdaPh#yup3ij*jDCu%Gs1`&yx+t+GHlgsyp|X?vKGmjXqwL4 zfa15`4;zP86EyYzj8~*FOR#sC@3_voE1ufnZS3Vt)K(= zYBY*(KO5#K4DXi61)*Pf~8%elfd^j=P!wG zT!;aF$;02)@P!t?jhsQ<7OY@Rfwfs&OOVXqC)%5Foy4^l-@yv-A&YOfRX;{iYU3Li zOYvz0dTHq7#J?eY^YiQ%qz$u(m?3qs!mzX?kJQ6ABiO)OZb%BgFS_`^`UKzDS1(Ha zQddgaT!255(Poqy+7}w2u44 ziStI+4rdhm@5P-FXUcn*Bhz?NQSh5U8$P7rO$z>0qZP~%FHbr9b+nwv1m42pIt7n( zcjWL`;oP-dTV-(U?-|mc^XoaZSKp~myYcm3LH-x<$75m=5t)^^&d&4i=J From 8015c3cf28e80b40bdcc4fb0f96b8a7754dcf63e Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 20 Jun 2023 13:01:01 +0200 Subject: [PATCH 251/364] QL language ref: explain implicit this receivers --- .../codeql/ql-language-reference/formulas.rst | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/codeql/ql-language-reference/formulas.rst b/docs/codeql/ql-language-reference/formulas.rst index cdc8c297b7d..8745217decc 100644 --- a/docs/codeql/ql-language-reference/formulas.rst +++ b/docs/codeql/ql-language-reference/formulas.rst @@ -164,6 +164,38 @@ If the call resolves to a predicate without result, then the call is a formula. It is also possible to call a predicate with result. This kind of call is an expression in QL, instead of a formula. For more information, see ":ref:`calls-with-result`." +Member predicates only apply to members of a particular class and calls to +member predicates have a receiver of a matching type. Syntactically, if a call +contains a dot, then the expression before the dot specifies the receiver of +the call. For instance, ``x`` is the receiver for the call ``x.isEven()``. + +For calls to member predicates of the enclosing class on the member itself +(i.e., the value of ``this``), the receiver may be omitted syntactically. In +this case we say the call has an implicit this receiver. For instance, in the +following example the ``isEven()`` call in ``isOdd()`` is a member predicate +call with an implicit this receiver and the call is equivalent to +``this.isEven()``: + +.. code-block:: ql + + class OneTwoThree extends int { + OneTwoThree() { this = 1 or this = 2 or this = 3 } + + predicate isEven() { this = 2 } + + predicate isOdd() { not isEven() } + } + +Use of implicit this receivers can make it harder to spot predicates that introduce +cartesian products by failing to relate the implicit ``this`` variable with +other variables, which can negatively affect query performance. For more +information on cartesian products, see ":ref:`Troubleshooting query performance +`". + +It is possible to enable warnings about implicit this receivers for `CodeQL packs +`__ +through the ``warnOnImplicitThis`` property. + .. _parenthesized-formulas: Parenthesized formulas From e332a4348d464d33a81695c36ca07c0add5d907a Mon Sep 17 00:00:00 2001 From: Adrien Pessu <7055334+adrienpessu@users.noreply.github.com> Date: Wed, 21 Jun 2023 12:55:33 +0100 Subject: [PATCH 252/364] Update javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp Co-authored-by: Erik Krogh Kristensen --- javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp index d3689155c00..adcd6fc4715 100644 --- a/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp +++ b/javascript/ql/src/Security/CWE-798/HardcodedCredentials.qhelp @@ -23,7 +23,7 @@

    - The following code example connects to an HTTP request using an hard-codes authentication header + The following code example connects to an HTTP request using an hard-codes authentication header:

    From 6d3f9fc67ef9a3d86545cdf5dc8f278ad28e1a93 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Wed, 21 Jun 2023 13:59:49 +0200 Subject: [PATCH 253/364] Polish QL language spec "Call with results" section --- .../ql-language-specification.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst index 71dcbdce571..04d58626474 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -1236,15 +1236,15 @@ The type environment for the arguments is the same as for the call. A valid call with results *resolves* to a set of predicates. The ways a call can resolve are as follows: -- If the call has no receiver and the predicate name is a simple identifier, then the predicate is resolved by looking up its name and arity in the visible member-predicate environment of the enclosing class. +- If the call has no receiver and the predicate reference is a simple identifier, then the call is resolved by looking up the predicate reference and arity in the visible predicate environment of the enclosing class. -- If the call has no receiver and the predicate name is a simple identifier, then the predicate is resolved by looking up its name and arity in the visible predicate environment of the enclosing module. +- If the call has no receiver and the predicate reference is a simple identifier, then the call is resolved by looking up the predicate reference and arity in the visible predicate environment of the enclosing module. -- If the call has no receiver and the predicate name is a selection identifier, then the qualifier is resolved as a module (see "`Module resolution <#module-resolution>`__"). The identifier is then resolved in the exported predicate environment of the qualifier module. +- If the call has no receiver and the predicate reference is a selection identifier, then the qualifier is resolved as a module (see "`Module resolution <#module-resolution>`__") and the call is resolved by looking up the identifier in the exported predicate environment of the qualifier module. -- If the type of the receiver is the same as the enclosing class, the predicate is resolved by looking up its name and arity in the visible predicate environment of the class. +- If the the call has a receiver and the type of the receiver is the same as the enclosing class, the call is resolved by looking up the predicate name and arity in the visible predicate environment of the enclosing class. -- If the type of the receiver is not the same as the enclosing class, the predicate is resolved by looking up its name and arity in the exported predicate environment of the class or domain type. +- If the the call has a receiver and the type of the receiver is not the same as the enclosing class, the call is resolved by looking up the predicate name and arity in the exported predicate environment of the type of the receiver. If all the predicates that the call resolves to are declared on a primitive type, we then restrict to the set of predicates where each argument of the call is a subtype of the corresponding predicate argument type. Then we find all predicates ``p`` from this new set such that there is not another predicate ``p'`` where each argument of ``p'`` is a subtype of the corresponding argument in ``p``. We then say the call resolves to this set instead. From 58c9bf4b12f644acabcee9f8d3f2075e4449064c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 20 Jun 2023 16:00:07 +0100 Subject: [PATCH 254/364] Swift: Copy the 'parse' test from Ruby. --- .../test/library-tests/regex/parse.expected | 6256 +++++++++++++++++ swift/ql/test/library-tests/regex/parse.ql | 27 + 2 files changed, 6283 insertions(+) create mode 100644 swift/ql/test/library-tests/regex/parse.expected create mode 100644 swift/ql/test/library-tests/regex/parse.ql diff --git a/swift/ql/test/library-tests/regex/parse.expected b/swift/ql/test/library-tests/regex/parse.expected new file mode 100644 index 00000000000..15ccb286286 --- /dev/null +++ b/swift/ql/test/library-tests/regex/parse.expected @@ -0,0 +1,6256 @@ +redos_variants.swift: +# 44| [RegExpDot] . + +# 44| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 46| [RegExpConstant, RegExpNormalChar] a + +# 46| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 46| [RegExpSequence] a*b +#-----| 0 -> [RegExpStar] a* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 46| [RegExpConstant, RegExpNormalChar] b + +# 47| [RegExpGroup] (a*) +#-----| 0 -> [RegExpStar] a* + +# 47| [RegExpSequence] (a*)b +#-----| 0 -> [RegExpGroup] (a*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 47| [RegExpConstant, RegExpNormalChar] a + +# 47| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 47| [RegExpConstant, RegExpNormalChar] b + +# 48| [RegExpGroup] (a) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 48| [RegExpStar] (a)* +#-----| 0 -> [RegExpGroup] (a) + +# 48| [RegExpSequence] (a)*b +#-----| 0 -> [RegExpStar] (a)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 48| [RegExpConstant, RegExpNormalChar] a + +# 48| [RegExpConstant, RegExpNormalChar] b + +# 49| [RegExpGroup] (a*) +#-----| 0 -> [RegExpStar] a* + +# 49| [RegExpStar] (a*)* +#-----| 0 -> [RegExpGroup] (a*) + +# 49| [RegExpSequence] (a*)*b +#-----| 0 -> [RegExpStar] (a*)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 49| [RegExpConstant, RegExpNormalChar] a + +# 49| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 49| [RegExpConstant, RegExpNormalChar] b + +# 50| [RegExpGroup] ((a*)*b) +#-----| 0 -> [RegExpSequence] (a*)*b + +# 50| [RegExpGroup] (a*) +#-----| 0 -> [RegExpStar] a* + +# 50| [RegExpStar] (a*)* +#-----| 0 -> [RegExpGroup] (a*) + +# 50| [RegExpSequence] (a*)*b +#-----| 0 -> [RegExpStar] (a*)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 50| [RegExpConstant, RegExpNormalChar] a + +# 50| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 50| [RegExpConstant, RegExpNormalChar] b + +# 52| [RegExpGroup] (a|aa?) +#-----| 0 -> [RegExpAlt] a|aa? + +# 52| [RegExpSequence] (a|aa?)b +#-----| 0 -> [RegExpGroup] (a|aa?) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 52| [RegExpConstant, RegExpNormalChar] a + +# 52| [RegExpConstant, RegExpNormalChar] a + +# 52| [RegExpConstant, RegExpNormalChar] a + +# 52| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 52| [RegExpSequence] aa? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpOpt] a? + +# 52| [RegExpAlt] a|aa? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpSequence] aa? + +# 52| [RegExpConstant, RegExpNormalChar] b + +# 53| [RegExpGroup] (a|aa?) +#-----| 0 -> [RegExpAlt] a|aa? + +# 53| [RegExpStar] (a|aa?)* +#-----| 0 -> [RegExpGroup] (a|aa?) + +# 53| [RegExpSequence] (a|aa?)*b +#-----| 0 -> [RegExpStar] (a|aa?)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 53| [RegExpConstant, RegExpNormalChar] a + +# 53| [RegExpConstant, RegExpNormalChar] a + +# 53| [RegExpConstant, RegExpNormalChar] a + +# 53| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 53| [RegExpSequence] aa? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpOpt] a? + +# 53| [RegExpAlt] a|aa? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpSequence] aa? + +# 53| [RegExpConstant, RegExpNormalChar] b + +# 58| [RegExpDollar] $ + +# 58| [RegExpGroup] (__|.) +#-----| 0 -> [RegExpAlt] __|. + +# 58| [RegExpPlus] (__|.)+ +#-----| 0 -> [RegExpGroup] (__|.) + +# 58| [RegExpDot] . + +# 58| [RegExpCaret] ^ + +# 58| [RegExpSequence] ^_(__|.)+_$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 2 -> [RegExpPlus] (__|.)+ +#-----| 3 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 4 -> [RegExpDollar] $ + +# 58| [RegExpConstant, RegExpNormalChar] _ + +# 58| [RegExpConstant, RegExpNormalChar] _ + +# 58| [RegExpConstant, RegExpNormalChar] __ + +# 58| [RegExpAlt] __|. +#-----| 0 -> [RegExpConstant, RegExpNormalChar] __ +#-----| 1 -> [RegExpDot] . + +# 59| [RegExpDollar] $ + +# 59| [RegExpGroup] (__|[^_]) +#-----| 0 -> [RegExpAlt] __|[^_] + +# 59| [RegExpPlus] (__|[^_])+ +#-----| 0 -> [RegExpGroup] (__|[^_]) + +# 59| [RegExpCharacterClass] [^_] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] _ + +# 59| [RegExpCaret] ^ + +# 59| [RegExpSequence] ^_(__|[^_])+_$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 2 -> [RegExpPlus] (__|[^_])+ +#-----| 3 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 4 -> [RegExpDollar] $ + +# 59| [RegExpConstant, RegExpNormalChar] _ + +# 59| [RegExpConstant, RegExpNormalChar] _ + +# 59| [RegExpConstant, RegExpNormalChar] _ + +# 59| [RegExpConstant, RegExpNormalChar] __ + +# 59| [RegExpAlt] __|[^_] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] __ +#-----| 1 -> [RegExpCharacterClass] [^_] + +# 66| [RegExpGroup] ((?:\*\*|[\s\S])+?) +#-----| 0 -> [RegExpPlus] (?:\*\*|[\s\S])+? + +# 66| [RegExpGroup] ((?:__|[\s\S])+?) +#-----| 0 -> [RegExpPlus] (?:__|[\s\S])+? + +# 66| [RegExpNegativeLookahead] (?!\*) + +# 66| [RegExpGroup] (?:\*\*|[\s\S]) +#-----| 0 -> [RegExpAlt] \*\*|[\s\S] + +# 66| [RegExpPlus] (?:\*\*|[\s\S])+? +#-----| 0 -> [RegExpGroup] (?:\*\*|[\s\S]) + +# 66| [RegExpGroup] (?:__|[\s\S]) +#-----| 0 -> [RegExpAlt] __|[\s\S] + +# 66| [RegExpPlus] (?:__|[\s\S])+? +#-----| 0 -> [RegExpGroup] (?:__|[\s\S]) + +# 66| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 66| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 66| [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpSequence] \*\* +#-----| 0 -> [RegExpConstant, RegExpEscape] \* +#-----| 1 -> [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpAlt] \*\*|[\s\S] +#-----| 0 -> [RegExpSequence] \*\* +#-----| 1 -> [RegExpCharacterClass] [\s\S] + +# 66| [RegExpCharacterClassEscape] \S + +# 66| [RegExpCharacterClassEscape] \S + +# 66| [RegExpSpecialChar] \b + +# 66| [RegExpSpecialChar] \b + +# 66| [RegExpCharacterClassEscape] \s + +# 66| [RegExpCharacterClassEscape] \s + +# 66| [RegExpCaret] ^ + +# 66| [RegExpCaret] ^ + +# 66| [RegExpSequence] ^\*((?:\*\*|[\s\S])+?)\*(?!\*) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpConstant, RegExpEscape] \* +#-----| 2 -> [RegExpGroup] ((?:\*\*|[\s\S])+?) +#-----| 3 -> [RegExpConstant, RegExpEscape] \* +#-----| 4 -> [RegExpNegativeLookahead] (?!\*) + +# 66| [RegExpSequence] ^\b_((?:__|[\s\S])+?)_\b +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpSpecialChar] \b +#-----| 2 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 3 -> [RegExpGroup] ((?:__|[\s\S])+?) +#-----| 4 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 5 -> [RegExpSpecialChar] \b + +# 66| [RegExpAlt] ^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*) +#-----| 0 -> [RegExpSequence] ^\b_((?:__|[\s\S])+?)_\b +#-----| 1 -> [RegExpSequence] ^\*((?:\*\*|[\s\S])+?)\*(?!\*) + +# 66| [RegExpConstant, RegExpNormalChar] _ + +# 66| [RegExpConstant, RegExpNormalChar] _ + +# 66| [RegExpConstant, RegExpNormalChar] __ + +# 66| [RegExpAlt] __|[\s\S] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] __ +#-----| 1 -> [RegExpCharacterClass] [\s\S] + +# 69| [RegExpGroup] ((?:\*\*|[\s\S])+?) +#-----| 0 -> [RegExpPlus] (?:\*\*|[\s\S])+? + +# 69| [RegExpGroup] ((?:__|[\s\S])+?) +#-----| 0 -> [RegExpPlus] (?:__|[\s\S])+? + +# 69| [RegExpNegativeLookahead] (?!\*) + +# 69| [RegExpGroup] (?:\*\*|[\s\S]) +#-----| 0 -> [RegExpAlt] \*\*|[\s\S] + +# 69| [RegExpPlus] (?:\*\*|[\s\S])+? +#-----| 0 -> [RegExpGroup] (?:\*\*|[\s\S]) + +# 69| [RegExpGroup] (?:__|[\s\S]) +#-----| 0 -> [RegExpAlt] __|[\s\S] + +# 69| [RegExpPlus] (?:__|[\s\S])+? +#-----| 0 -> [RegExpGroup] (?:__|[\s\S]) + +# 69| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 69| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 69| [RegExpConstant, RegExpEscape] \* + +# 69| [RegExpConstant, RegExpEscape] \* + +# 69| [RegExpConstant, RegExpEscape] \* + +# 69| [RegExpConstant, RegExpEscape] \* + +# 69| [RegExpConstant, RegExpEscape] \* + +# 69| [RegExpSequence] \*\* +#-----| 0 -> [RegExpConstant, RegExpEscape] \* +#-----| 1 -> [RegExpConstant, RegExpEscape] \* + +# 69| [RegExpAlt] \*\*|[\s\S] +#-----| 0 -> [RegExpSequence] \*\* +#-----| 1 -> [RegExpCharacterClass] [\s\S] + +# 69| [RegExpCharacterClassEscape] \S + +# 69| [RegExpCharacterClassEscape] \S + +# 69| [RegExpSpecialChar] \b + +# 69| [RegExpSpecialChar] \b + +# 69| [RegExpCharacterClassEscape] \s + +# 69| [RegExpCharacterClassEscape] \s + +# 69| [RegExpCaret] ^ + +# 69| [RegExpCaret] ^ + +# 69| [RegExpSequence] ^\*((?:\*\*|[\s\S])+?)\*(?!\*) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpConstant, RegExpEscape] \* +#-----| 2 -> [RegExpGroup] ((?:\*\*|[\s\S])+?) +#-----| 3 -> [RegExpConstant, RegExpEscape] \* +#-----| 4 -> [RegExpNegativeLookahead] (?!\*) + +# 69| [RegExpSequence] ^\b_((?:__|[\s\S])+?)_\b +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpSpecialChar] \b +#-----| 2 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 3 -> [RegExpGroup] ((?:__|[\s\S])+?) +#-----| 4 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 5 -> [RegExpSpecialChar] \b + +# 69| [RegExpAlt] ^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*) +#-----| 0 -> [RegExpSequence] ^\b_((?:__|[\s\S])+?)_\b +#-----| 1 -> [RegExpSequence] ^\*((?:\*\*|[\s\S])+?)\*(?!\*) + +# 69| [RegExpConstant, RegExpNormalChar] _ + +# 69| [RegExpConstant, RegExpNormalChar] _ + +# 69| [RegExpConstant, RegExpNormalChar] __ + +# 69| [RegExpAlt] __|[\s\S] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] __ +#-----| 1 -> [RegExpCharacterClass] [\s\S] + +# 74| [RegExpGroup] ((?:\*\*|[^*])+?) +#-----| 0 -> [RegExpPlus] (?:\*\*|[^*])+? + +# 74| [RegExpGroup] ((?:__|[^_])+?) +#-----| 0 -> [RegExpPlus] (?:__|[^_])+? + +# 74| [RegExpNegativeLookahead] (?!\*) + +# 74| [RegExpGroup] (?:\*\*|[^*]) +#-----| 0 -> [RegExpAlt] \*\*|[^*] + +# 74| [RegExpPlus] (?:\*\*|[^*])+? +#-----| 0 -> [RegExpGroup] (?:\*\*|[^*]) + +# 74| [RegExpGroup] (?:__|[^_]) +#-----| 0 -> [RegExpAlt] __|[^_] + +# 74| [RegExpPlus] (?:__|[^_])+? +#-----| 0 -> [RegExpGroup] (?:__|[^_]) + +# 74| [RegExpConstant, RegExpNormalChar] * + +# 74| [RegExpCharacterClass] [^*] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] * + +# 74| [RegExpCharacterClass] [^_] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] _ + +# 74| [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpSequence] \*\* +#-----| 0 -> [RegExpConstant, RegExpEscape] \* +#-----| 1 -> [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpAlt] \*\*|[^*] +#-----| 0 -> [RegExpSequence] \*\* +#-----| 1 -> [RegExpCharacterClass] [^*] + +# 74| [RegExpSpecialChar] \b + +# 74| [RegExpSpecialChar] \b + +# 74| [RegExpCaret] ^ + +# 74| [RegExpCaret] ^ + +# 74| [RegExpSequence] ^\*((?:\*\*|[^*])+?)\*(?!\*) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpConstant, RegExpEscape] \* +#-----| 2 -> [RegExpGroup] ((?:\*\*|[^*])+?) +#-----| 3 -> [RegExpConstant, RegExpEscape] \* +#-----| 4 -> [RegExpNegativeLookahead] (?!\*) + +# 74| [RegExpSequence] ^\b_((?:__|[^_])+?)_\b +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpSpecialChar] \b +#-----| 2 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 3 -> [RegExpGroup] ((?:__|[^_])+?) +#-----| 4 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 5 -> [RegExpSpecialChar] \b + +# 74| [RegExpAlt] ^\b_((?:__|[^_])+?)_\b|^\*((?:\*\*|[^*])+?)\*(?!\*) +#-----| 0 -> [RegExpSequence] ^\b_((?:__|[^_])+?)_\b +#-----| 1 -> [RegExpSequence] ^\*((?:\*\*|[^*])+?)\*(?!\*) + +# 74| [RegExpConstant, RegExpNormalChar] _ + +# 74| [RegExpConstant, RegExpNormalChar] _ + +# 74| [RegExpConstant, RegExpNormalChar] _ + +# 74| [RegExpConstant, RegExpNormalChar] __ + +# 74| [RegExpAlt] __|[^_] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] __ +#-----| 1 -> [RegExpCharacterClass] [^_] + +# 79| [RegExpGroup] (.*,) +#-----| 0 -> [RegExpSequence] .*, + +# 79| [RegExpPlus] (.*,)+ +#-----| 0 -> [RegExpGroup] (.*,) + +# 79| [RegExpSequence] (.*,)+.+ +#-----| 0 -> [RegExpPlus] (.*,)+ +#-----| 1 -> [RegExpPlus] .+ + +# 79| [RegExpConstant, RegExpNormalChar] , + +# 79| [RegExpDot] . + +# 79| [RegExpDot] . + +# 79| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 79| [RegExpSequence] .*, +#-----| 0 -> [RegExpStar] .* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] , + +# 79| [RegExpPlus] .+ +#-----| 0 -> [RegExpDot] . + +# 85| [RegExpConstant, RegExpNormalChar] " + +# 85| [RegExpConstant, RegExpNormalChar] " + +# 85| [RegExpConstant, RegExpNormalChar] " + +# 85| [RegExpSequence] "(?:[^"\\]|\\\\|\\.)+" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpPlus] (?:[^"\\]|\\\\|\\.)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 85| [RegExpAlt] "(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\) +#-----| 0 -> [RegExpSequence] "(?:[^"\\]|\\\\|\\.)+" +#-----| 1 -> [RegExpSequence] '(?:[^'\\]|\\\\|\\.)+' +#-----| 2 -> [RegExpSequence] \((?:[^)\\]|\\\\|\\.)+\) + +# 85| [RegExpConstant, RegExpNormalChar] ' + +# 85| [RegExpConstant, RegExpNormalChar] ' + +# 85| [RegExpConstant, RegExpNormalChar] ' + +# 85| [RegExpSequence] '(?:[^'\\]|\\\\|\\.)+' +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ' +#-----| 1 -> [RegExpPlus] (?:[^'\\]|\\\\|\\.)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] ' + +# 85| [RegExpGroup] (?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) +#-----| 0 -> [RegExpAlt] "(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\) + +# 85| [RegExpGroup] (?:[^"\\]|\\\\|\\.) +#-----| 0 -> [RegExpAlt] [^"\\]|\\\\|\\. + +# 85| [RegExpPlus] (?:[^"\\]|\\\\|\\.)+ +#-----| 0 -> [RegExpGroup] (?:[^"\\]|\\\\|\\.) + +# 85| [RegExpGroup] (?:[^'\\]|\\\\|\\.) +#-----| 0 -> [RegExpAlt] [^'\\]|\\\\|\\. + +# 85| [RegExpPlus] (?:[^'\\]|\\\\|\\.)+ +#-----| 0 -> [RegExpGroup] (?:[^'\\]|\\\\|\\.) + +# 85| [RegExpGroup] (?:[^)\\]|\\\\|\\.) +#-----| 0 -> [RegExpAlt] [^)\\]|\\\\|\\. + +# 85| [RegExpPlus] (?:[^)\\]|\\\\|\\.)+ +#-----| 0 -> [RegExpGroup] (?:[^)\\]|\\\\|\\.) + +# 85| [RegExpGroup] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\))) +#-----| 0 -> [RegExpSequence] \s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) + +# 85| [RegExpOpt] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))? +#-----| 0 -> [RegExpGroup] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\))) + +# 85| [RegExpConstant, RegExpNormalChar] ) + +# 85| [RegExpDot] . + +# 85| [RegExpDot] . + +# 85| [RegExpDot] . + +# 85| [RegExpCharacterClass] [^"\\] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpAlt] [^"\\]|\\\\|\\. +#-----| 0 -> [RegExpCharacterClass] [^"\\] +#-----| 1 -> [RegExpSequence] \\\\ +#-----| 2 -> [RegExpSequence] \\. + +# 85| [RegExpCharacterClass] [^'\\] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ' +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpAlt] [^'\\]|\\\\|\\. +#-----| 0 -> [RegExpCharacterClass] [^'\\] +#-----| 1 -> [RegExpSequence] \\\\ +#-----| 2 -> [RegExpSequence] \\. + +# 85| [RegExpCharacterClass] [^)\\] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ) +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpAlt] [^)\\]|\\\\|\\. +#-----| 0 -> [RegExpCharacterClass] [^)\\] +#-----| 1 -> [RegExpSequence] \\\\ +#-----| 2 -> [RegExpSequence] \\. + +# 85| [RegExpConstant, RegExpEscape] \( + +# 85| [RegExpSequence] \((?:[^)\\]|\\\\|\\.)+\) +#-----| 0 -> [RegExpConstant, RegExpEscape] \( +#-----| 1 -> [RegExpPlus] (?:[^)\\]|\\\\|\\.)+ +#-----| 2 -> [RegExpConstant, RegExpEscape] \) + +# 85| [RegExpConstant, RegExpEscape] \) + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpSequence] \\. +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpDot] . + +# 85| [RegExpSequence] \\. +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpDot] . + +# 85| [RegExpSequence] \\. +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpDot] . + +# 85| [RegExpSequence] \\\\ +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpSequence] \\\\ +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpSequence] \\\\ +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpCharacterClassEscape] \s + +# 85| [RegExpPlus] \s+ +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 85| [RegExpSequence] \s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) +#-----| 0 -> [RegExpPlus] \s+ +#-----| 1 -> [RegExpGroup] (?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) + +# 85| [RegExpCaret] ^ + +# 85| [RegExpSequence] ^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))? +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpOpt] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))? + +# 90| [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpStar] * +#-----| 0 -> [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpStar] * +#-----| 0 -> [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpStar] * +#-----| 0 -> [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpDollar] $ + +# 90| [RegExpGroup] ((?:.*\|.*(?:\n|$))*) +#-----| 0 -> [RegExpStar] (?:.*\|.*(?:\n|$))* + +# 90| [RegExpGroup] (?:.*\|.*(?:\n|$)) +#-----| 0 -> [RegExpSequence] .*\|.*(?:\n|$) + +# 90| [RegExpStar] (?:.*\|.*(?:\n|$))* +#-----| 0 -> [RegExpGroup] (?:.*\|.*(?:\n|$)) + +# 90| [RegExpGroup] (?:\n|$) +#-----| 0 -> [RegExpAlt] \n|$ + +# 90| [RegExpGroup] ([-:]+ *\|[-| :]*) +#-----| 0 -> [RegExpSequence] [-:]+ *\|[-| :]* + +# 90| [RegExpGroup] (\S.*\|.*) +#-----| 0 -> [RegExpSequence] \S.*\|.* + +# 90| [RegExpConstant, RegExpNormalChar] - + +# 90| [RegExpConstant, RegExpNormalChar] - + +# 90| [RegExpDot] . + +# 90| [RegExpDot] . + +# 90| [RegExpDot] . + +# 90| [RegExpDot] . + +# 90| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 90| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 90| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 90| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 90| [RegExpSequence] .*\|.*(?:\n|$) +#-----| 0 -> [RegExpStar] .* +#-----| 1 -> [RegExpConstant, RegExpEscape] \| +#-----| 2 -> [RegExpStar] .* +#-----| 3 -> [RegExpGroup] (?:\n|$) + +# 90| [RegExpConstant, RegExpNormalChar] : + +# 90| [RegExpConstant, RegExpNormalChar] : + +# 90| [RegExpCharacterClass] [-:] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] - +#-----| 1 -> [RegExpConstant, RegExpNormalChar] : + +# 90| [RegExpPlus] [-:]+ +#-----| 0 -> [RegExpCharacterClass] [-:] + +# 90| [RegExpSequence] [-:]+ *\|[-| :]* +#-----| 0 -> [RegExpPlus] [-:]+ +#-----| 1 -> [RegExpStar] * +#-----| 2 -> [RegExpConstant, RegExpEscape] \| +#-----| 3 -> [RegExpStar] [-| :]* + +# 90| [RegExpCharacterClass] [-| :] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] - +#-----| 1 -> [RegExpConstant, RegExpNormalChar] | +#-----| 2 -> [RegExpConstant, RegExpNormalChar] +#-----| 3 -> [RegExpConstant, RegExpNormalChar] : + +# 90| [RegExpStar] [-| :]* +#-----| 0 -> [RegExpCharacterClass] [-| :] + +# 90| [RegExpCharacterClassEscape] \S + +# 90| [RegExpSequence] \S.*\|.* +#-----| 0 -> [RegExpCharacterClassEscape] \S +#-----| 1 -> [RegExpStar] .* +#-----| 2 -> [RegExpConstant, RegExpEscape] \| +#-----| 3 -> [RegExpStar] .* + +# 90| [RegExpConstant, RegExpEscape] \n + +# 90| [RegExpConstant, RegExpEscape] \n + +# 90| [RegExpConstant, RegExpEscape] \n + +# 90| [RegExpConstant, RegExpEscape] \n + +# 90| [RegExpStar] \n* +#-----| 0 -> [RegExpConstant, RegExpEscape] \n + +# 90| [RegExpAlt] \n|$ +#-----| 0 -> [RegExpConstant, RegExpEscape] \n +#-----| 1 -> [RegExpDollar] $ + +# 90| [RegExpConstant, RegExpEscape] \| + +# 90| [RegExpConstant, RegExpEscape] \| + +# 90| [RegExpConstant, RegExpEscape] \| + +# 90| [RegExpCaret] ^ + +# 90| [RegExpSequence] ^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n* +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpStar] * +#-----| 2 -> [RegExpGroup] (\S.*\|.*) +#-----| 3 -> [RegExpConstant, RegExpEscape] \n +#-----| 4 -> [RegExpStar] * +#-----| 5 -> [RegExpGroup] ([-:]+ *\|[-| :]*) +#-----| 6 -> [RegExpConstant, RegExpEscape] \n +#-----| 7 -> [RegExpGroup] ((?:.*\|.*(?:\n|$))*) +#-----| 8 -> [RegExpStar] \n* + +# 90| [RegExpConstant, RegExpNormalChar] | + +# 96| [RegExpConstant, RegExpNormalChar] + +# 96| [RegExpDollar] $ + +# 96| [RegExpNegativeLookahead] (?![ *]) + +# 96| [RegExpPositiveLookahead] (?=\W|$) + +# 96| [RegExpGroup] (\\\/|.) +#-----| 0 -> [RegExpAlt] \\\/|. + +# 96| [RegExpStar] (\\\/|.)*? +#-----| 0 -> [RegExpGroup] (\\\/|.) + +# 96| [RegExpConstant, RegExpNormalChar] * + +# 96| [RegExpDot] . + +# 96| [RegExpCharacterClass] [ *] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] * + +# 96| [RegExpCharacterClass] [gim] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] g +#-----| 1 -> [RegExpConstant, RegExpNormalChar] i +#-----| 2 -> [RegExpConstant, RegExpNormalChar] m + +# 96| [RegExpStar] [gim]* +#-----| 0 -> [RegExpCharacterClass] [gim] + +# 96| [RegExpConstant, RegExpEscape] \/ + +# 96| [RegExpConstant, RegExpEscape] \/ + +# 96| [RegExpConstant, RegExpEscape] \/ + +# 96| [RegExpSequence] \/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$) +#-----| 0 -> [RegExpConstant, RegExpEscape] \/ +#-----| 1 -> [RegExpNegativeLookahead] (?![ *]) +#-----| 2 -> [RegExpStar] (\\\/|.)*? +#-----| 3 -> [RegExpConstant, RegExpEscape] \/ +#-----| 4 -> [RegExpStar] [gim]* +#-----| 5 -> [RegExpPositiveLookahead] (?=\W|$) + +# 96| [RegExpCharacterClassEscape] \W + +# 96| [RegExpAlt] \W|$ +#-----| 0 -> [RegExpCharacterClassEscape] \W +#-----| 1 -> [RegExpDollar] $ + +# 96| [RegExpConstant, RegExpEscape] \\ + +# 96| [RegExpSequence] \\\/ +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpEscape] \/ + +# 96| [RegExpAlt] \\\/|. +#-----| 0 -> [RegExpSequence] \\\/ +#-----| 1 -> [RegExpDot] . + +# 96| [RegExpConstant, RegExpNormalChar] g + +# 96| [RegExpConstant, RegExpNormalChar] i + +# 96| [RegExpConstant, RegExpNormalChar] m + +# 102| [RegExpConstant, RegExpNormalChar] # + +# 102| [RegExpSequence] #.* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] # +#-----| 1 -> [RegExpStar] .* + +# 102| [RegExpDollar] $ + +# 102| [RegExpGroup] ([\s\[\{\(]|#.*) +#-----| 0 -> [RegExpAlt] [\s\[\{\(]|#.* + +# 102| [RegExpStar] ([\s\[\{\(]|#.*)* +#-----| 0 -> [RegExpGroup] ([\s\[\{\(]|#.*) + +# 102| [RegExpDot] . + +# 102| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 102| [RegExpCharacterClass] [\s\[\{\(] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpConstant, RegExpEscape] \[ +#-----| 2 -> [RegExpConstant, RegExpEscape] \{ +#-----| 3 -> [RegExpConstant, RegExpEscape] \( + +# 102| [RegExpAlt] [\s\[\{\(]|#.* +#-----| 0 -> [RegExpCharacterClass] [\s\[\{\(] +#-----| 1 -> [RegExpSequence] #.* + +# 102| [RegExpConstant, RegExpEscape] \( + +# 102| [RegExpConstant, RegExpEscape] \[ + +# 102| [RegExpCharacterClassEscape] \s + +# 102| [RegExpConstant, RegExpEscape] \{ + +# 102| [RegExpCaret] ^ + +# 102| [RegExpSequence] ^([\s\[\{\(]|#.*)*$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpStar] ([\s\[\{\(]|#.*)* +#-----| 2 -> [RegExpDollar] $ + +# 108| [RegExpConstant, RegExpNormalChar] $ + +# 108| [RegExpConstant, RegExpNormalChar] $ + +# 108| [RegExpConstant, RegExpNormalChar] $ + +# 108| [RegExpConstant, RegExpNormalChar] $ + +# 108| [RegExpDollar] $ + +# 108| [RegExpGroup] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*) +#-----| 0 -> [RegExpSequence] \.[\_$a-z][\_$a-z0-9]*(\[.*?\])* + +# 108| [RegExpStar] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)* +#-----| 0 -> [RegExpGroup] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*) + +# 108| [RegExpGroup] (\[.*?\]) +#-----| 0 -> [RegExpSequence] \[.*?\] + +# 108| [RegExpGroup] (\[.*?\]) +#-----| 0 -> [RegExpSequence] \[.*?\] + +# 108| [RegExpStar] (\[.*?\])* +#-----| 0 -> [RegExpGroup] (\[.*?\]) + +# 108| [RegExpStar] (\[.*?\])* +#-----| 0 -> [RegExpGroup] (\[.*?\]) + +# 108| [RegExpDot] . + +# 108| [RegExpDot] . + +# 108| [RegExpStar] .*? +#-----| 0 -> [RegExpDot] . + +# 108| [RegExpStar] .*? +#-----| 0 -> [RegExpDot] . + +# 108| [RegExpConstant, RegExpNormalChar] 0 + +# 108| [RegExpConstant, RegExpNormalChar] 0 + +# 108| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 108| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 108| [RegExpConstant, RegExpNormalChar] 9 + +# 108| [RegExpConstant, RegExpNormalChar] 9 + +# 108| [RegExpCharacterClass] [\_$a-z0-9] +#-----| 0 -> [RegExpConstant, RegExpEscape] \_ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ +#-----| 2 -> [RegExpCharacterRange] a-z +#-----| 3 -> [RegExpCharacterRange] 0-9 + +# 108| [RegExpCharacterClass] [\_$a-z0-9] +#-----| 0 -> [RegExpConstant, RegExpEscape] \_ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ +#-----| 2 -> [RegExpCharacterRange] a-z +#-----| 3 -> [RegExpCharacterRange] 0-9 + +# 108| [RegExpStar] [\_$a-z0-9]* +#-----| 0 -> [RegExpCharacterClass] [\_$a-z0-9] + +# 108| [RegExpStar] [\_$a-z0-9]* +#-----| 0 -> [RegExpCharacterClass] [\_$a-z0-9] + +# 108| [RegExpCharacterClass] [\_$a-z] +#-----| 0 -> [RegExpConstant, RegExpEscape] \_ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ +#-----| 2 -> [RegExpCharacterRange] a-z + +# 108| [RegExpCharacterClass] [\_$a-z] +#-----| 0 -> [RegExpConstant, RegExpEscape] \_ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ +#-----| 2 -> [RegExpCharacterRange] a-z + +# 108| [RegExpConstant, RegExpEscape] \. + +# 108| [RegExpSequence] \.[\_$a-z][\_$a-z0-9]*(\[.*?\])* +#-----| 0 -> [RegExpConstant, RegExpEscape] \. +#-----| 1 -> [RegExpCharacterClass] [\_$a-z] +#-----| 2 -> [RegExpStar] [\_$a-z0-9]* +#-----| 3 -> [RegExpStar] (\[.*?\])* + +# 108| [RegExpConstant, RegExpEscape] \[ + +# 108| [RegExpConstant, RegExpEscape] \[ + +# 108| [RegExpSequence] \[.*?\] +#-----| 0 -> [RegExpConstant, RegExpEscape] \[ +#-----| 1 -> [RegExpStar] .*? +#-----| 2 -> [RegExpConstant, RegExpEscape] \] + +# 108| [RegExpSequence] \[.*?\] +#-----| 0 -> [RegExpConstant, RegExpEscape] \[ +#-----| 1 -> [RegExpStar] .*? +#-----| 2 -> [RegExpConstant, RegExpEscape] \] + +# 108| [RegExpConstant, RegExpEscape] \] + +# 108| [RegExpConstant, RegExpEscape] \] + +# 108| [RegExpConstant, RegExpEscape] \_ + +# 108| [RegExpConstant, RegExpEscape] \_ + +# 108| [RegExpConstant, RegExpEscape] \_ + +# 108| [RegExpConstant, RegExpEscape] \_ + +# 108| [RegExpCaret] ^ + +# 108| [RegExpSequence] ^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpCharacterClass] [\_$a-z] +#-----| 2 -> [RegExpStar] [\_$a-z0-9]* +#-----| 3 -> [RegExpStar] (\[.*?\])* +#-----| 4 -> [RegExpStar] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)* +#-----| 5 -> [RegExpDollar] $ + +# 108| [RegExpConstant, RegExpNormalChar] a + +# 108| [RegExpConstant, RegExpNormalChar] a + +# 108| [RegExpConstant, RegExpNormalChar] a + +# 108| [RegExpConstant, RegExpNormalChar] a + +# 108| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 108| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 108| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 108| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 108| [RegExpConstant, RegExpNormalChar] z + +# 108| [RegExpConstant, RegExpNormalChar] z + +# 108| [RegExpConstant, RegExpNormalChar] z + +# 108| [RegExpConstant, RegExpNormalChar] z + +# 114| [RegExpConstant, RegExpNormalChar] # + +# 114| [RegExpDollar] $ + +# 114| [RegExpConstant, RegExpNormalChar] ( + +# 114| [RegExpGroup] (([\w#:.~>+()\s-]+|\*|\[.*?\])+) +#-----| 0 -> [RegExpPlus] ([\w#:.~>+()\s-]+|\*|\[.*?\])+ + +# 114| [RegExpSequence] (([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$) +#-----| 0 -> [RegExpGroup] (([\w#:.~>+()\s-]+|\*|\[.*?\])+) +#-----| 1 -> [RegExpStar] \s* +#-----| 2 -> [RegExpGroup] (,|$) + +# 114| [RegExpGroup] (,|$) +#-----| 0 -> [RegExpAlt] ,|$ + +# 114| [RegExpGroup] ([\w#:.~>+()\s-]+|\*|\[.*?\]) +#-----| 0 -> [RegExpAlt] [\w#:.~>+()\s-]+|\*|\[.*?\] + +# 114| [RegExpPlus] ([\w#:.~>+()\s-]+|\*|\[.*?\])+ +#-----| 0 -> [RegExpGroup] ([\w#:.~>+()\s-]+|\*|\[.*?\]) + +# 114| [RegExpConstant, RegExpNormalChar] ) + +# 114| [RegExpConstant, RegExpNormalChar] + + +# 114| [RegExpConstant, RegExpNormalChar] , + +# 114| [RegExpAlt] ,|$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] , +#-----| 1 -> [RegExpDollar] $ + +# 114| [RegExpConstant, RegExpNormalChar] - + +# 114| [RegExpConstant, RegExpNormalChar] . + +# 114| [RegExpDot] . + +# 114| [RegExpStar] .*? +#-----| 0 -> [RegExpDot] . + +# 114| [RegExpConstant, RegExpNormalChar] : + +# 114| [RegExpConstant, RegExpNormalChar] > + +# 114| [RegExpCharacterClass] [\w#:.~>+()\s-] +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpNormalChar] # +#-----| 2 -> [RegExpConstant, RegExpNormalChar] : +#-----| 3 -> [RegExpConstant, RegExpNormalChar] . +#-----| 4 -> [RegExpConstant, RegExpNormalChar] ~ +#-----| 5 -> [RegExpConstant, RegExpNormalChar] > +#-----| 6 -> [RegExpConstant, RegExpNormalChar] + +#-----| 7 -> [RegExpConstant, RegExpNormalChar] ( +#-----| 8 -> [RegExpConstant, RegExpNormalChar] ) +#-----| 9 -> [RegExpCharacterClassEscape] \s +#-----| 10 -> [RegExpConstant, RegExpNormalChar] - + +# 114| [RegExpPlus] [\w#:.~>+()\s-]+ +#-----| 0 -> [RegExpCharacterClass] [\w#:.~>+()\s-] + +# 114| [RegExpAlt] [\w#:.~>+()\s-]+|\*|\[.*?\] +#-----| 0 -> [RegExpPlus] [\w#:.~>+()\s-]+ +#-----| 1 -> [RegExpConstant, RegExpEscape] \* +#-----| 2 -> [RegExpSequence] \[.*?\] + +# 114| [RegExpConstant, RegExpEscape] \* + +# 114| [RegExpConstant, RegExpEscape] \[ + +# 114| [RegExpSequence] \[.*?\] +#-----| 0 -> [RegExpConstant, RegExpEscape] \[ +#-----| 1 -> [RegExpStar] .*? +#-----| 2 -> [RegExpConstant, RegExpEscape] \] + +# 114| [RegExpConstant, RegExpEscape] \] + +# 114| [RegExpCharacterClassEscape] \s + +# 114| [RegExpCharacterClassEscape] \s + +# 114| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 114| [RegExpCharacterClassEscape] \w + +# 114| [RegExpConstant, RegExpNormalChar] ~ + +# 120| [RegExpConstant, RegExpNormalChar] " + +# 120| [RegExpAlt] "|' +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpConstant, RegExpNormalChar] ' + +# 120| [RegExpConstant, RegExpNormalChar] ' + +# 120| [RegExpGroup] ("|') +#-----| 0 -> [RegExpAlt] "|' + +# 120| [RegExpSequence] ("|')(\\?.)*?\1 +#-----| 0 -> [RegExpGroup] ("|') +#-----| 1 -> [RegExpStar] (\\?.)*? +#-----| 2 -> [RegExpBackRef] \1 + +# 120| [RegExpGroup] (\\?.) +#-----| 0 -> [RegExpSequence] \\?. + +# 120| [RegExpStar] (\\?.)*? +#-----| 0 -> [RegExpGroup] (\\?.) + +# 120| [RegExpDot] . + +# 120| [RegExpBackRef] \1 + +# 120| [RegExpConstant, RegExpEscape] \\ + +# 120| [RegExpOpt] \\? +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ + +# 120| [RegExpSequence] \\?. +#-----| 0 -> [RegExpOpt] \\? +#-----| 1 -> [RegExpDot] . + +# 125| [RegExpGroup] (\r\n|\r|\n) +#-----| 0 -> [RegExpAlt] \r\n|\r|\n + +# 125| [RegExpPlus] (\r\n|\r|\n)+ +#-----| 0 -> [RegExpGroup] (\r\n|\r|\n) + +# 125| [RegExpConstant, RegExpEscape] \n + +# 125| [RegExpConstant, RegExpEscape] \n + +# 125| [RegExpConstant, RegExpEscape] \r + +# 125| [RegExpConstant, RegExpEscape] \r + +# 125| [RegExpSequence] \r\n +#-----| 0 -> [RegExpConstant, RegExpEscape] \r +#-----| 1 -> [RegExpConstant, RegExpEscape] \n + +# 125| [RegExpAlt] \r\n|\r|\n +#-----| 0 -> [RegExpSequence] \r\n +#-----| 1 -> [RegExpConstant, RegExpEscape] \r +#-----| 2 -> [RegExpConstant, RegExpEscape] \n + +# 128| [RegExpGroup] (a|.) +#-----| 0 -> [RegExpAlt] a|. + +# 128| [RegExpStar] (a|.)* +#-----| 0 -> [RegExpGroup] (a|.) + +# 128| [RegExpDot] . + +# 128| [RegExpConstant, RegExpNormalChar] a + +# 128| [RegExpAlt] a|. +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpDot] . + +# 132| [RegExpDollar] $ + +# 132| [RegExpGroup] ([a-z]+) +#-----| 0 -> [RegExpPlus] [a-z]+ + +# 132| [RegExpPlus] ([a-z]+)+ +#-----| 0 -> [RegExpGroup] ([a-z]+) + +# 132| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 132| [RegExpPlus] [a-z]+ +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 132| [RegExpCaret] ^ + +# 132| [RegExpSequence] ^([a-z]+)+$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ([a-z]+)+ +#-----| 2 -> [RegExpDollar] $ + +# 132| [RegExpConstant, RegExpNormalChar] a + +# 132| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 132| [RegExpConstant, RegExpNormalChar] z + +# 133| [RegExpDollar] $ + +# 133| [RegExpGroup] ([a-z]*) +#-----| 0 -> [RegExpStar] [a-z]* + +# 133| [RegExpStar] ([a-z]*)* +#-----| 0 -> [RegExpGroup] ([a-z]*) + +# 133| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 133| [RegExpStar] [a-z]* +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 133| [RegExpCaret] ^ + +# 133| [RegExpSequence] ^([a-z]*)*$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpStar] ([a-z]*)* +#-----| 2 -> [RegExpDollar] $ + +# 133| [RegExpConstant, RegExpNormalChar] a + +# 133| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 133| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpDollar] $ + +# 134| [RegExpGroup] (([\\.-]|[_]+)?([a-zA-Z0-9]+)) +#-----| 0 -> [RegExpSequence] ([\\.-]|[_]+)?([a-zA-Z0-9]+) + +# 134| [RegExpStar] (([\\.-]|[_]+)?([a-zA-Z0-9]+))* +#-----| 0 -> [RegExpGroup] (([\\.-]|[_]+)?([a-zA-Z0-9]+)) + +# 134| [RegExpGroup] (([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3})) +#-----| 0 -> [RegExpAlt] ([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}) + +# 134| [RegExpGroup] (@) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] @ + +# 134| [RegExpRange] (@){1} +#-----| 0 -> [RegExpGroup] (@) + +# 134| [RegExpGroup] ([\\.-]|[_]+) +#-----| 0 -> [RegExpAlt] [\\.-]|[_]+ + +# 134| [RegExpOpt] ([\\.-]|[_]+)? +#-----| 0 -> [RegExpGroup] ([\\.-]|[_]+) + +# 134| [RegExpSequence] ([\\.-]|[_]+)?([a-zA-Z0-9]+) +#-----| 0 -> [RegExpOpt] ([\\.-]|[_]+)? +#-----| 1 -> [RegExpGroup] ([a-zA-Z0-9]+) + +# 134| [RegExpGroup] ([a-zA-Z0-9]) +#-----| 0 -> [RegExpCharacterClass] [a-zA-Z0-9] + +# 134| [RegExpGroup] ([a-zA-Z0-9]+) +#-----| 0 -> [RegExpPlus] [a-zA-Z0-9]+ + +# 134| [RegExpGroup] ([a-z]{2,3}) +#-----| 0 -> [RegExpRange] [a-z]{2,3} + +# 134| [RegExpAlt] ([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}) +#-----| 0 -> [RegExpGroup] ([a-z]{2,3}) +#-----| 1 -> [RegExpGroup] ([a-z]{2,3}[.]{1}[a-z]{2,3}) + +# 134| [RegExpGroup] ([a-z]{2,3}[.]{1}[a-z]{2,3}) +#-----| 0 -> [RegExpSequence] [a-z]{2,3}[.]{1}[a-z]{2,3} + +# 134| [RegExpConstant, RegExpNormalChar] - + +# 134| [RegExpConstant, RegExpNormalChar] . + +# 134| [RegExpConstant, RegExpNormalChar] . + +# 134| [RegExpConstant, RegExpNormalChar] . + +# 134| [RegExpConstant, RegExpNormalChar] 0 + +# 134| [RegExpConstant, RegExpNormalChar] 0 + +# 134| [RegExpConstant, RegExpNormalChar] 0 + +# 134| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpConstant, RegExpNormalChar] @ + +# 134| [RegExpConstant, RegExpNormalChar] A + +# 134| [RegExpConstant, RegExpNormalChar] A + +# 134| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 134| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 134| [RegExpConstant, RegExpNormalChar] Z + +# 134| [RegExpConstant, RegExpNormalChar] Z + +# 134| [RegExpCharacterClass] [.] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] . + +# 134| [RegExpCharacterClass] [.] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] . + +# 134| [RegExpRange] [.]{1} +#-----| 0 -> [RegExpCharacterClass] [.] + +# 134| [RegExpRange] [.]{1} +#-----| 0 -> [RegExpCharacterClass] [.] + +# 134| [RegExpCharacterClass] [\\.-] +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] . +#-----| 2 -> [RegExpConstant, RegExpNormalChar] - + +# 134| [RegExpAlt] [\\.-]|[_]+ +#-----| 0 -> [RegExpCharacterClass] [\\.-] +#-----| 1 -> [RegExpPlus] [_]+ + +# 134| [RegExpCharacterClass] [_] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] _ + +# 134| [RegExpPlus] [_]+ +#-----| 0 -> [RegExpCharacterClass] [_] + +# 134| [RegExpCharacterClass] [a-z0-9] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] 0-9 + +# 134| [RegExpPlus] [a-z0-9]+ +#-----| 0 -> [RegExpCharacterClass] [a-z0-9] + +# 134| [RegExpCharacterClass] [a-zA-Z0-9] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z +#-----| 2 -> [RegExpCharacterRange] 0-9 + +# 134| [RegExpCharacterClass] [a-zA-Z0-9] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z +#-----| 2 -> [RegExpCharacterRange] 0-9 + +# 134| [RegExpPlus] [a-zA-Z0-9]+ +#-----| 0 -> [RegExpCharacterClass] [a-zA-Z0-9] + +# 134| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 134| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 134| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 134| [RegExpRange] [a-z]{2,3} +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 134| [RegExpRange] [a-z]{2,3} +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 134| [RegExpRange] [a-z]{2,3} +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 134| [RegExpSequence] [a-z]{2,3}[.]{1}[a-z]{2,3} +#-----| 0 -> [RegExpRange] [a-z]{2,3} +#-----| 1 -> [RegExpRange] [.]{1} +#-----| 2 -> [RegExpRange] [a-z]{2,3} + +# 134| [RegExpConstant, RegExpEscape] \\ + +# 134| [RegExpCaret] ^ + +# 134| [RegExpSequence] ^([a-zA-Z0-9])(([\\.-]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpGroup] ([a-zA-Z0-9]) +#-----| 2 -> [RegExpStar] (([\\.-]|[_]+)?([a-zA-Z0-9]+))* +#-----| 3 -> [RegExpRange] (@){1} +#-----| 4 -> [RegExpPlus] [a-z0-9]+ +#-----| 5 -> [RegExpRange] [.]{1} +#-----| 6 -> [RegExpGroup] (([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3})) +#-----| 7 -> [RegExpDollar] $ + +# 134| [RegExpConstant, RegExpNormalChar] _ + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 135| [RegExpDollar] $ + +# 135| [RegExpGroup] (([a-z])+.) +#-----| 0 -> [RegExpSequence] ([a-z])+. + +# 135| [RegExpPlus] (([a-z])+.)+ +#-----| 0 -> [RegExpGroup] (([a-z])+.) + +# 135| [RegExpGroup] ([a-z]) +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 135| [RegExpGroup] ([a-z]) +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 135| [RegExpPlus] ([a-z])+ +#-----| 0 -> [RegExpGroup] ([a-z]) + +# 135| [RegExpPlus] ([a-z])+ +#-----| 0 -> [RegExpGroup] ([a-z]) + +# 135| [RegExpSequence] ([a-z])+. +#-----| 0 -> [RegExpPlus] ([a-z])+ +#-----| 1 -> [RegExpDot] . + +# 135| [RegExpDot] . + +# 135| [RegExpConstant, RegExpNormalChar] A + +# 135| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 135| [RegExpConstant, RegExpNormalChar] Z + +# 135| [RegExpCharacterClass] [A-Z] +#-----| 0 -> [RegExpCharacterRange] A-Z + +# 135| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 135| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 135| [RegExpCaret] ^ + +# 135| [RegExpSequence] ^(([a-z])+.)+[A-Z]([a-z])+$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] (([a-z])+.)+ +#-----| 2 -> [RegExpCharacterClass] [A-Z] +#-----| 3 -> [RegExpPlus] ([a-z])+ +#-----| 4 -> [RegExpDollar] $ + +# 135| [RegExpConstant, RegExpNormalChar] a + +# 135| [RegExpConstant, RegExpNormalChar] a + +# 135| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 135| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 135| [RegExpConstant, RegExpNormalChar] z + +# 135| [RegExpConstant, RegExpNormalChar] z + +# 139| [RegExpGroup] (b|a?b) +#-----| 0 -> [RegExpAlt] b|a?b + +# 139| [RegExpStar] (b|a?b)* +#-----| 0 -> [RegExpGroup] (b|a?b) + +# 139| [RegExpSequence] (b|a?b)*c +#-----| 0 -> [RegExpStar] (b|a?b)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] c + +# 139| [RegExpConstant, RegExpNormalChar] a + +# 139| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 139| [RegExpSequence] a?b +#-----| 0 -> [RegExpOpt] a? +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 139| [RegExpConstant, RegExpNormalChar] b + +# 139| [RegExpConstant, RegExpNormalChar] b + +# 139| [RegExpAlt] b|a?b +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b +#-----| 1 -> [RegExpSequence] a?b + +# 139| [RegExpConstant, RegExpNormalChar] c + +# 142| [RegExpConstant, RegExpNormalChar] ! + +# 142| [RegExpGroup] (.|\n) +#-----| 0 -> [RegExpAlt] .|\n + +# 142| [RegExpStar] (.|\n)* +#-----| 0 -> [RegExpGroup] (.|\n) + +# 142| [RegExpSequence] (.|\n)*! +#-----| 0 -> [RegExpStar] (.|\n)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] ! + +# 142| [RegExpDot] . + +# 142| [RegExpAlt] .|\n +#-----| 0 -> [RegExpDot] . +#-----| 1 -> [RegExpConstant, RegExpEscape] \n + +# 142| [RegExpConstant, RegExpEscape] \n + +# 146| [RegExpConstant, RegExpNormalChar] ! + +# 146| [RegExpGroup] (.|\n) +#-----| 0 -> [RegExpAlt] .|\n + +# 146| [RegExpStar] (.|\n)* +#-----| 0 -> [RegExpGroup] (.|\n) + +# 146| [RegExpDot] . + +# 146| [RegExpAlt] .|\n +#-----| 0 -> [RegExpDot] . +#-----| 1 -> [RegExpConstant, RegExpEscape] \n + +# 146| [RegExpConstant, RegExpEscape] \n + +# 146| [RegExpConstant, RegExpNormalChar] s + +# 149| [RegExpGroup] ([\w.]+) +#-----| 0 -> [RegExpPlus] [\w.]+ + +# 149| [RegExpStar] ([\w.]+)* +#-----| 0 -> [RegExpGroup] ([\w.]+) + +# 149| [RegExpConstant, RegExpNormalChar] . + +# 149| [RegExpCharacterClass] [\w.] +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpNormalChar] . + +# 149| [RegExpPlus] [\w.]+ +#-----| 0 -> [RegExpCharacterClass] [\w.] + +# 149| [RegExpCharacterClassEscape] \w + +# 152| [RegExpGroup] ([\w.]+) +#-----| 0 -> [RegExpPlus] [\w.]+ + +# 152| [RegExpStar] ([\w.]+)* +#-----| 0 -> [RegExpGroup] ([\w.]+) + +# 152| [RegExpConstant, RegExpNormalChar] . + +# 152| [RegExpCharacterClass] [\w.] +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpNormalChar] . + +# 152| [RegExpPlus] [\w.]+ +#-----| 0 -> [RegExpCharacterClass] [\w.] + +# 152| [RegExpCharacterClassEscape] \w + +# 156| [RegExpConstant, RegExpNormalChar] " + +# 156| [RegExpGroup] (([\s\S]|[^a])*) +#-----| 0 -> [RegExpStar] ([\s\S]|[^a])* + +# 156| [RegExpSequence] (([\s\S]|[^a])*)" +#-----| 0 -> [RegExpGroup] (([\s\S]|[^a])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 156| [RegExpGroup] ([\s\S]|[^a]) +#-----| 0 -> [RegExpAlt] [\s\S]|[^a] + +# 156| [RegExpStar] ([\s\S]|[^a])* +#-----| 0 -> [RegExpGroup] ([\s\S]|[^a]) + +# 156| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 156| [RegExpAlt] [\s\S]|[^a] +#-----| 0 -> [RegExpCharacterClass] [\s\S] +#-----| 1 -> [RegExpCharacterClass] [^a] + +# 156| [RegExpCharacterClass] [^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 156| [RegExpCharacterClassEscape] \S + +# 156| [RegExpCharacterClassEscape] \s + +# 156| [RegExpConstant, RegExpNormalChar] a + +# 159| [RegExpConstant, RegExpNormalChar] " + +# 159| [RegExpConstant, RegExpNormalChar] ' + +# 159| [RegExpGroup] ([^"']+) +#-----| 0 -> [RegExpPlus] [^"']+ + +# 159| [RegExpStar] ([^"']+)* +#-----| 0 -> [RegExpGroup] ([^"']+) + +# 159| [RegExpCharacterClass] [^"'] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpConstant, RegExpNormalChar] ' + +# 159| [RegExpPlus] [^"']+ +#-----| 0 -> [RegExpCharacterClass] [^"'] + +# 163| [RegExpConstant, RegExpNormalChar] " + +# 163| [RegExpGroup] ((.|[^a])*) +#-----| 0 -> [RegExpStar] (.|[^a])* + +# 163| [RegExpSequence] ((.|[^a])*)" +#-----| 0 -> [RegExpGroup] ((.|[^a])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 163| [RegExpGroup] (.|[^a]) +#-----| 0 -> [RegExpAlt] .|[^a] + +# 163| [RegExpStar] (.|[^a])* +#-----| 0 -> [RegExpGroup] (.|[^a]) + +# 163| [RegExpDot] . + +# 163| [RegExpAlt] .|[^a] +#-----| 0 -> [RegExpDot] . +#-----| 1 -> [RegExpCharacterClass] [^a] + +# 163| [RegExpCharacterClass] [^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 163| [RegExpConstant, RegExpNormalChar] a + +# 166| [RegExpConstant, RegExpNormalChar] " + +# 166| [RegExpGroup] ((a|[^a])*) +#-----| 0 -> [RegExpStar] (a|[^a])* + +# 166| [RegExpSequence] ((a|[^a])*)" +#-----| 0 -> [RegExpGroup] ((a|[^a])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 166| [RegExpGroup] (a|[^a]) +#-----| 0 -> [RegExpAlt] a|[^a] + +# 166| [RegExpStar] (a|[^a])* +#-----| 0 -> [RegExpGroup] (a|[^a]) + +# 166| [RegExpCharacterClass] [^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 166| [RegExpConstant, RegExpNormalChar] a + +# 166| [RegExpConstant, RegExpNormalChar] a + +# 166| [RegExpAlt] a|[^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpCharacterClass] [^a] + +# 170| [RegExpConstant, RegExpNormalChar] " + +# 170| [RegExpGroup] ((b|[^a])*) +#-----| 0 -> [RegExpStar] (b|[^a])* + +# 170| [RegExpSequence] ((b|[^a])*)" +#-----| 0 -> [RegExpGroup] ((b|[^a])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 170| [RegExpGroup] (b|[^a]) +#-----| 0 -> [RegExpAlt] b|[^a] + +# 170| [RegExpStar] (b|[^a])* +#-----| 0 -> [RegExpGroup] (b|[^a]) + +# 170| [RegExpCharacterClass] [^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 170| [RegExpConstant, RegExpNormalChar] a + +# 170| [RegExpConstant, RegExpNormalChar] b + +# 170| [RegExpAlt] b|[^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b +#-----| 1 -> [RegExpCharacterClass] [^a] + +# 174| [RegExpConstant, RegExpNormalChar] " + +# 174| [RegExpGroup] ((G|[^a])*) +#-----| 0 -> [RegExpStar] (G|[^a])* + +# 174| [RegExpSequence] ((G|[^a])*)" +#-----| 0 -> [RegExpGroup] ((G|[^a])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 174| [RegExpGroup] (G|[^a]) +#-----| 0 -> [RegExpAlt] G|[^a] + +# 174| [RegExpStar] (G|[^a])* +#-----| 0 -> [RegExpGroup] (G|[^a]) + +# 174| [RegExpConstant, RegExpNormalChar] G + +# 174| [RegExpAlt] G|[^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] G +#-----| 1 -> [RegExpCharacterClass] [^a] + +# 174| [RegExpCharacterClass] [^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 174| [RegExpConstant, RegExpNormalChar] a + +# 178| [RegExpConstant, RegExpNormalChar] " + +# 178| [RegExpGroup] (([0-9]|[^a])*) +#-----| 0 -> [RegExpStar] ([0-9]|[^a])* + +# 178| [RegExpSequence] (([0-9]|[^a])*)" +#-----| 0 -> [RegExpGroup] (([0-9]|[^a])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 178| [RegExpGroup] ([0-9]|[^a]) +#-----| 0 -> [RegExpAlt] [0-9]|[^a] + +# 178| [RegExpStar] ([0-9]|[^a])* +#-----| 0 -> [RegExpGroup] ([0-9]|[^a]) + +# 178| [RegExpConstant, RegExpNormalChar] 0 + +# 178| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 178| [RegExpConstant, RegExpNormalChar] 9 + +# 178| [RegExpCharacterClass] [0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 178| [RegExpAlt] [0-9]|[^a] +#-----| 0 -> [RegExpCharacterClass] [0-9] +#-----| 1 -> [RegExpCharacterClass] [^a] + +# 178| [RegExpCharacterClass] [^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 178| [RegExpConstant, RegExpNormalChar] a + +# 182| [RegExpConstant, RegExpNormalChar] ! + +# 182| [RegExpConstant, RegExpNormalChar] " + +# 182| [RegExpConstant, RegExpNormalChar] " + +# 182| [RegExpConstant, RegExpNormalChar] " + +# 182| [RegExpSequence] "((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpGroup] ((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*) +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 182| [RegExpConstant, RegExpNormalChar] # + +# 182| [RegExpConstant, RegExpNormalChar] % + +# 182| [RegExpConstant, RegExpNormalChar] & + +# 182| [RegExpConstant, RegExpNormalChar] ' + +# 182| [RegExpGroup] ((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*) +#-----| 0 -> [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])* + +# 182| [RegExpGroup] (?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") +#-----| 0 -> [RegExpAlt] ([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)" + +# 182| [RegExpGroup] (?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)")) +#-----| 0 -> [RegExpSequence] =(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") + +# 182| [RegExpOpt] (?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"))? +#-----| 0 -> [RegExpGroup] (?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)")) + +# 182| [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"]) +#-----| 0 -> [RegExpAlt] \\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"] + +# 182| [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])* +#-----| 0 -> [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"]) + +# 182| [RegExpGroup] ([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) +#-----| 0 -> [RegExpPlus] [!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+ + +# 182| [RegExpAlt] ([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)" +#-----| 0 -> [RegExpGroup] ([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) +#-----| 1 -> [RegExpSequence] "((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)" + +# 182| [RegExpConstant, RegExpNormalChar] 0 + +# 182| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 182| [RegExpConstant, RegExpNormalChar] 9 + +# 182| [RegExpConstant, RegExpNormalChar] = + +# 182| [RegExpSequence] =(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") +#-----| 0 -> [RegExpConstant, RegExpNormalChar] = +#-----| 1 -> [RegExpGroup] (?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") + +# 182| [RegExpConstant, RegExpNormalChar] A + +# 182| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 182| [RegExpConstant, RegExpNormalChar] Z + +# 182| [RegExpCharacterClass] [!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ! +#-----| 1 -> [RegExpConstant, RegExpNormalChar] # +#-----| 2 -> [RegExpConstant, RegExpEscape] \$ +#-----| 3 -> [RegExpConstant, RegExpNormalChar] % +#-----| 4 -> [RegExpConstant, RegExpNormalChar] & +#-----| 5 -> [RegExpConstant, RegExpNormalChar] ' +#-----| 6 -> [RegExpConstant, RegExpEscape] \* +#-----| 7 -> [RegExpConstant, RegExpEscape] \+ +#-----| 8 -> [RegExpConstant, RegExpEscape] \- +#-----| 9 -> [RegExpConstant, RegExpEscape] \. +#-----| 10 -> [RegExpConstant, RegExpEscape] \^ +#-----| 11 -> [RegExpConstant, RegExpNormalChar] _ +#-----| 12 -> [RegExpConstant, RegExpNormalChar] ` +#-----| 13 -> [RegExpConstant, RegExpEscape] \| +#-----| 14 -> [RegExpConstant, RegExpNormalChar] ~ +#-----| 15 -> [RegExpCharacterRange] 0-9 +#-----| 16 -> [RegExpCharacterRange] A-Z +#-----| 17 -> [RegExpCharacterRange] a-z + +# 182| [RegExpPlus] [!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+ +#-----| 0 -> [RegExpCharacterClass] [!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z] + +# 182| [RegExpCharacterClass] [\x00-\x7f] +#-----| 0 -> [RegExpCharacterRange] \x00-\x7f + +# 182| [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"] +#-----| 0 -> [RegExpCharacterRange] \x00-\x08 +#-----| 1 -> [RegExpCharacterRange] \x0a-\x1f +#-----| 2 -> [RegExpConstant, RegExpEscape] \x7f +#-----| 3 -> [RegExpConstant, RegExpNormalChar] " + +# 182| [RegExpConstant, RegExpEscape] \$ + +# 182| [RegExpConstant, RegExpEscape] \* + +# 182| [RegExpConstant, RegExpEscape] \+ + +# 182| [RegExpConstant, RegExpEscape] \- + +# 182| [RegExpConstant, RegExpEscape] \. + +# 182| [RegExpConstant, RegExpEscape] \\ + +# 182| [RegExpSequence] \\[\x00-\x7f] +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpCharacterClass] [\x00-\x7f] + +# 182| [RegExpAlt] \\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"] +#-----| 0 -> [RegExpSequence] \\[\x00-\x7f] +#-----| 1 -> [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"] + +# 182| [RegExpConstant, RegExpEscape] \^ + +# 182| [RegExpConstant, RegExpEscape] \x00 + +# 182| [RegExpConstant, RegExpEscape] \x00 + +# 182| [RegExpCharacterRange] \x00-\x08 +#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 +#-----| 1 -> [RegExpConstant, RegExpEscape] \x08 + +# 182| [RegExpCharacterRange] \x00-\x7f +#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 +#-----| 1 -> [RegExpConstant, RegExpEscape] \x7f + +# 182| [RegExpConstant, RegExpEscape] \x08 + +# 182| [RegExpConstant, RegExpEscape] \x0a + +# 182| [RegExpCharacterRange] \x0a-\x1f +#-----| 0 -> [RegExpConstant, RegExpEscape] \x0a +#-----| 1 -> [RegExpConstant, RegExpEscape] \x1f + +# 182| [RegExpConstant, RegExpEscape] \x1f + +# 182| [RegExpConstant, RegExpEscape] \x7f + +# 182| [RegExpConstant, RegExpEscape] \x7f + +# 182| [RegExpConstant, RegExpEscape] \| + +# 182| [RegExpConstant, RegExpNormalChar] _ + +# 182| [RegExpConstant, RegExpNormalChar] ` + +# 182| [RegExpConstant, RegExpNormalChar] a + +# 182| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 182| [RegExpConstant, RegExpNormalChar] z + +# 182| [RegExpConstant, RegExpNormalChar] ~ + +# 186| [RegExpConstant, RegExpNormalChar] " + +# 186| [RegExpConstant, RegExpNormalChar] " + +# 186| [RegExpConstant, RegExpNormalChar] " + +# 186| [RegExpSequence] "((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpGroup] ((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*) +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 186| [RegExpGroup] ((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*) +#-----| 0 -> [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])* + +# 186| [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"]) +#-----| 0 -> [RegExpAlt] \\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"] + +# 186| [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])* +#-----| 0 -> [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"]) + +# 186| [RegExpCharacterClass] [\x00-\x7f] +#-----| 0 -> [RegExpCharacterRange] \x00-\x7f + +# 186| [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"] +#-----| 0 -> [RegExpCharacterRange] \x00-\x08 +#-----| 1 -> [RegExpCharacterRange] \x0a-\x1f +#-----| 2 -> [RegExpConstant, RegExpEscape] \x7f +#-----| 3 -> [RegExpConstant, RegExpNormalChar] " + +# 186| [RegExpConstant, RegExpEscape] \\ + +# 186| [RegExpSequence] \\[\x00-\x7f] +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpCharacterClass] [\x00-\x7f] + +# 186| [RegExpAlt] \\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"] +#-----| 0 -> [RegExpSequence] \\[\x00-\x7f] +#-----| 1 -> [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"] + +# 186| [RegExpConstant, RegExpEscape] \x00 + +# 186| [RegExpConstant, RegExpEscape] \x00 + +# 186| [RegExpCharacterRange] \x00-\x08 +#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 +#-----| 1 -> [RegExpConstant, RegExpEscape] \x08 + +# 186| [RegExpCharacterRange] \x00-\x7f +#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 +#-----| 1 -> [RegExpConstant, RegExpEscape] \x7f + +# 186| [RegExpConstant, RegExpEscape] \x08 + +# 186| [RegExpConstant, RegExpEscape] \x0a + +# 186| [RegExpCharacterRange] \x0a-\x1f +#-----| 0 -> [RegExpConstant, RegExpEscape] \x0a +#-----| 1 -> [RegExpConstant, RegExpEscape] \x1f + +# 186| [RegExpConstant, RegExpEscape] \x1f + +# 186| [RegExpConstant, RegExpEscape] \x7f + +# 186| [RegExpConstant, RegExpEscape] \x7f + +# 189| [RegExpConstant, RegExpNormalChar] " + +# 189| [RegExpConstant, RegExpNormalChar] " + +# 189| [RegExpConstant, RegExpNormalChar] " + +# 189| [RegExpSequence] "((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*)" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpGroup] ((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*) +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 189| [RegExpGroup] ((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*) +#-----| 0 -> [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])* + +# 189| [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\]) +#-----| 0 -> [RegExpAlt] \\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\] + +# 189| [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])* +#-----| 0 -> [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\]) + +# 189| [RegExpCharacterClass] [\x00-\x7f] +#-----| 0 -> [RegExpCharacterRange] \x00-\x7f + +# 189| [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"\\] +#-----| 0 -> [RegExpCharacterRange] \x00-\x08 +#-----| 1 -> [RegExpCharacterRange] \x0a-\x1f +#-----| 2 -> [RegExpConstant, RegExpEscape] \x7f +#-----| 3 -> [RegExpConstant, RegExpNormalChar] " +#-----| 4 -> [RegExpConstant, RegExpEscape] \\ + +# 189| [RegExpConstant, RegExpEscape] \\ + +# 189| [RegExpConstant, RegExpEscape] \\ + +# 189| [RegExpSequence] \\[\x00-\x7f] +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpCharacterClass] [\x00-\x7f] + +# 189| [RegExpAlt] \\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\] +#-----| 0 -> [RegExpSequence] \\[\x00-\x7f] +#-----| 1 -> [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"\\] + +# 189| [RegExpConstant, RegExpEscape] \x00 + +# 189| [RegExpConstant, RegExpEscape] \x00 + +# 189| [RegExpCharacterRange] \x00-\x08 +#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 +#-----| 1 -> [RegExpConstant, RegExpEscape] \x08 + +# 189| [RegExpCharacterRange] \x00-\x7f +#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 +#-----| 1 -> [RegExpConstant, RegExpEscape] \x7f + +# 189| [RegExpConstant, RegExpEscape] \x08 + +# 189| [RegExpConstant, RegExpEscape] \x0a + +# 189| [RegExpCharacterRange] \x0a-\x1f +#-----| 0 -> [RegExpConstant, RegExpEscape] \x0a +#-----| 1 -> [RegExpConstant, RegExpEscape] \x1f + +# 189| [RegExpConstant, RegExpEscape] \x1f + +# 189| [RegExpConstant, RegExpEscape] \x7f + +# 189| [RegExpConstant, RegExpEscape] \x7f + +# 193| [RegExpConstant, RegExpNormalChar] " + +# 193| [RegExpGroup] (([a-z]|[d-h])*) +#-----| 0 -> [RegExpStar] ([a-z]|[d-h])* + +# 193| [RegExpSequence] (([a-z]|[d-h])*)" +#-----| 0 -> [RegExpGroup] (([a-z]|[d-h])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 193| [RegExpGroup] ([a-z]|[d-h]) +#-----| 0 -> [RegExpAlt] [a-z]|[d-h] + +# 193| [RegExpStar] ([a-z]|[d-h])* +#-----| 0 -> [RegExpGroup] ([a-z]|[d-h]) + +# 193| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 193| [RegExpAlt] [a-z]|[d-h] +#-----| 0 -> [RegExpCharacterClass] [a-z] +#-----| 1 -> [RegExpCharacterClass] [d-h] + +# 193| [RegExpCharacterClass] [d-h] +#-----| 0 -> [RegExpCharacterRange] d-h + +# 193| [RegExpConstant, RegExpNormalChar] a + +# 193| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 193| [RegExpConstant, RegExpNormalChar] d + +# 193| [RegExpCharacterRange] d-h +#-----| 0 -> [RegExpConstant, RegExpNormalChar] d +#-----| 1 -> [RegExpConstant, RegExpNormalChar] h + +# 193| [RegExpConstant, RegExpNormalChar] h + +# 193| [RegExpConstant, RegExpNormalChar] z + +# 197| [RegExpConstant, RegExpNormalChar] " + +# 197| [RegExpGroup] (([^a-z]|[^0-9])*) +#-----| 0 -> [RegExpStar] ([^a-z]|[^0-9])* + +# 197| [RegExpSequence] (([^a-z]|[^0-9])*)" +#-----| 0 -> [RegExpGroup] (([^a-z]|[^0-9])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 197| [RegExpGroup] ([^a-z]|[^0-9]) +#-----| 0 -> [RegExpAlt] [^a-z]|[^0-9] + +# 197| [RegExpStar] ([^a-z]|[^0-9])* +#-----| 0 -> [RegExpGroup] ([^a-z]|[^0-9]) + +# 197| [RegExpConstant, RegExpNormalChar] 0 + +# 197| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 197| [RegExpConstant, RegExpNormalChar] 9 + +# 197| [RegExpCharacterClass] [^0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 197| [RegExpCharacterClass] [^a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 197| [RegExpAlt] [^a-z]|[^0-9] +#-----| 0 -> [RegExpCharacterClass] [^a-z] +#-----| 1 -> [RegExpCharacterClass] [^0-9] + +# 197| [RegExpConstant, RegExpNormalChar] a + +# 197| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 197| [RegExpConstant, RegExpNormalChar] z + +# 201| [RegExpConstant, RegExpNormalChar] " + +# 201| [RegExpGroup] ((\d|[0-9])*) +#-----| 0 -> [RegExpStar] (\d|[0-9])* + +# 201| [RegExpSequence] ((\d|[0-9])*)" +#-----| 0 -> [RegExpGroup] ((\d|[0-9])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 201| [RegExpGroup] (\d|[0-9]) +#-----| 0 -> [RegExpAlt] \d|[0-9] + +# 201| [RegExpStar] (\d|[0-9])* +#-----| 0 -> [RegExpGroup] (\d|[0-9]) + +# 201| [RegExpConstant, RegExpNormalChar] 0 + +# 201| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 201| [RegExpConstant, RegExpNormalChar] 9 + +# 201| [RegExpCharacterClass] [0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 201| [RegExpCharacterClassEscape] \d + +# 201| [RegExpAlt] \d|[0-9] +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpCharacterClass] [0-9] + +# 205| [RegExpConstant, RegExpNormalChar] " + +# 205| [RegExpGroup] ((\s|\s)*) +#-----| 0 -> [RegExpStar] (\s|\s)* + +# 205| [RegExpSequence] ((\s|\s)*)" +#-----| 0 -> [RegExpGroup] ((\s|\s)*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 205| [RegExpGroup] (\s|\s) +#-----| 0 -> [RegExpAlt] \s|\s + +# 205| [RegExpStar] (\s|\s)* +#-----| 0 -> [RegExpGroup] (\s|\s) + +# 205| [RegExpCharacterClassEscape] \s + +# 205| [RegExpCharacterClassEscape] \s + +# 205| [RegExpAlt] \s|\s +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \s + +# 209| [RegExpConstant, RegExpNormalChar] " + +# 209| [RegExpGroup] ((\w|G)*) +#-----| 0 -> [RegExpStar] (\w|G)* + +# 209| [RegExpSequence] ((\w|G)*)" +#-----| 0 -> [RegExpGroup] ((\w|G)*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 209| [RegExpGroup] (\w|G) +#-----| 0 -> [RegExpAlt] \w|G + +# 209| [RegExpStar] (\w|G)* +#-----| 0 -> [RegExpGroup] (\w|G) + +# 209| [RegExpConstant, RegExpNormalChar] G + +# 209| [RegExpCharacterClassEscape] \w + +# 209| [RegExpAlt] \w|G +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpNormalChar] G + +# 212| [RegExpConstant, RegExpNormalChar] " + +# 212| [RegExpGroup] ((\s|\d)*) +#-----| 0 -> [RegExpStar] (\s|\d)* + +# 212| [RegExpSequence] ((\s|\d)*)" +#-----| 0 -> [RegExpGroup] ((\s|\d)*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 212| [RegExpGroup] (\s|\d) +#-----| 0 -> [RegExpAlt] \s|\d + +# 212| [RegExpStar] (\s|\d)* +#-----| 0 -> [RegExpGroup] (\s|\d) + +# 212| [RegExpCharacterClassEscape] \d + +# 212| [RegExpCharacterClassEscape] \s + +# 212| [RegExpAlt] \s|\d +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \d + +# 216| [RegExpConstant, RegExpNormalChar] " + +# 216| [RegExpGroup] ((\d|\d)*) +#-----| 0 -> [RegExpStar] (\d|\d)* + +# 216| [RegExpSequence] ((\d|\d)*)" +#-----| 0 -> [RegExpGroup] ((\d|\d)*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 216| [RegExpGroup] (\d|\d) +#-----| 0 -> [RegExpAlt] \d|\d + +# 216| [RegExpStar] (\d|\d)* +#-----| 0 -> [RegExpGroup] (\d|\d) + +# 216| [RegExpCharacterClassEscape] \d + +# 216| [RegExpCharacterClassEscape] \d + +# 216| [RegExpAlt] \d|\d +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpCharacterClassEscape] \d + +# 220| [RegExpConstant, RegExpNormalChar] " + +# 220| [RegExpGroup] ((\d|\w)*) +#-----| 0 -> [RegExpStar] (\d|\w)* + +# 220| [RegExpSequence] ((\d|\w)*)" +#-----| 0 -> [RegExpGroup] ((\d|\w)*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 220| [RegExpGroup] (\d|\w) +#-----| 0 -> [RegExpAlt] \d|\w + +# 220| [RegExpStar] (\d|\w)* +#-----| 0 -> [RegExpGroup] (\d|\w) + +# 220| [RegExpCharacterClassEscape] \d + +# 220| [RegExpAlt] \d|\w +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpCharacterClassEscape] \w + +# 220| [RegExpCharacterClassEscape] \w + +# 224| [RegExpConstant, RegExpNormalChar] " + +# 224| [RegExpGroup] ((\d|5)*) +#-----| 0 -> [RegExpStar] (\d|5)* + +# 224| [RegExpSequence] ((\d|5)*)" +#-----| 0 -> [RegExpGroup] ((\d|5)*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 224| [RegExpGroup] (\d|5) +#-----| 0 -> [RegExpAlt] \d|5 + +# 224| [RegExpStar] (\d|5)* +#-----| 0 -> [RegExpGroup] (\d|5) + +# 224| [RegExpConstant, RegExpNormalChar] 5 + +# 224| [RegExpCharacterClassEscape] \d + +# 224| [RegExpAlt] \d|5 +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 5 + +# 228| [RegExpConstant, RegExpNormalChar] " + +# 228| [RegExpGroup] ((\s|[\f])*) +#-----| 0 -> [RegExpStar] (\s|[\f])* + +# 228| [RegExpSequence] ((\s|[\f])*)" +#-----| 0 -> [RegExpGroup] ((\s|[\f])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 228| [RegExpGroup] (\s|[\f]) +#-----| 0 -> [RegExpAlt] \s|[\f] + +# 228| [RegExpStar] (\s|[\f])* +#-----| 0 -> [RegExpGroup] (\s|[\f]) + +# 228| [RegExpCharacterClass] [\f] +#-----| 0 -> [RegExpConstant, RegExpEscape] \f + +# 228| [RegExpConstant, RegExpEscape] \f + +# 228| [RegExpCharacterClassEscape] \s + +# 228| [RegExpAlt] \s|[\f] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClass] [\f] + +# 232| [RegExpConstant, RegExpNormalChar] " + +# 232| [RegExpGroup] ((\s|[\v]|\\v)*) +#-----| 0 -> [RegExpStar] (\s|[\v]|\\v)* + +# 232| [RegExpSequence] ((\s|[\v]|\\v)*)" +#-----| 0 -> [RegExpGroup] ((\s|[\v]|\\v)*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 232| [RegExpGroup] (\s|[\v]|\\v) +#-----| 0 -> [RegExpAlt] \s|[\v]|\\v + +# 232| [RegExpStar] (\s|[\v]|\\v)* +#-----| 0 -> [RegExpGroup] (\s|[\v]|\\v) + +# 232| [RegExpCharacterClass] [\v] +#-----| 0 -> [RegExpConstant, RegExpEscape] \v + +# 232| [RegExpConstant, RegExpEscape] \\ + +# 232| [RegExpSequence] \\v +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] v + +# 232| [RegExpCharacterClassEscape] \s + +# 232| [RegExpAlt] \s|[\v]|\\v +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClass] [\v] +#-----| 2 -> [RegExpSequence] \\v + +# 232| [RegExpConstant, RegExpEscape] \v + +# 232| [RegExpConstant, RegExpNormalChar] v + +# 236| [RegExpConstant, RegExpNormalChar] " + +# 236| [RegExpGroup] ((\f|[\f])*) +#-----| 0 -> [RegExpStar] (\f|[\f])* + +# 236| [RegExpSequence] ((\f|[\f])*)" +#-----| 0 -> [RegExpGroup] ((\f|[\f])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 236| [RegExpGroup] (\f|[\f]) +#-----| 0 -> [RegExpAlt] \f|[\f] + +# 236| [RegExpStar] (\f|[\f])* +#-----| 0 -> [RegExpGroup] (\f|[\f]) + +# 236| [RegExpCharacterClass] [\f] +#-----| 0 -> [RegExpConstant, RegExpEscape] \f + +# 236| [RegExpConstant, RegExpEscape] \f + +# 236| [RegExpConstant, RegExpEscape] \f + +# 236| [RegExpAlt] \f|[\f] +#-----| 0 -> [RegExpConstant, RegExpEscape] \f +#-----| 1 -> [RegExpCharacterClass] [\f] + +# 240| [RegExpConstant, RegExpNormalChar] " + +# 240| [RegExpGroup] ((\W|\D)*) +#-----| 0 -> [RegExpStar] (\W|\D)* + +# 240| [RegExpSequence] ((\W|\D)*)" +#-----| 0 -> [RegExpGroup] ((\W|\D)*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 240| [RegExpGroup] (\W|\D) +#-----| 0 -> [RegExpAlt] \W|\D + +# 240| [RegExpStar] (\W|\D)* +#-----| 0 -> [RegExpGroup] (\W|\D) + +# 240| [RegExpCharacterClassEscape] \D + +# 240| [RegExpCharacterClassEscape] \W + +# 240| [RegExpAlt] \W|\D +#-----| 0 -> [RegExpCharacterClassEscape] \W +#-----| 1 -> [RegExpCharacterClassEscape] \D + +# 244| [RegExpConstant, RegExpNormalChar] " + +# 244| [RegExpGroup] ((\S|\w)*) +#-----| 0 -> [RegExpStar] (\S|\w)* + +# 244| [RegExpSequence] ((\S|\w)*)" +#-----| 0 -> [RegExpGroup] ((\S|\w)*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 244| [RegExpGroup] (\S|\w) +#-----| 0 -> [RegExpAlt] \S|\w + +# 244| [RegExpStar] (\S|\w)* +#-----| 0 -> [RegExpGroup] (\S|\w) + +# 244| [RegExpCharacterClassEscape] \S + +# 244| [RegExpAlt] \S|\w +#-----| 0 -> [RegExpCharacterClassEscape] \S +#-----| 1 -> [RegExpCharacterClassEscape] \w + +# 244| [RegExpCharacterClassEscape] \w + +# 248| [RegExpConstant, RegExpNormalChar] " + +# 248| [RegExpGroup] ((\S|[\w])*) +#-----| 0 -> [RegExpStar] (\S|[\w])* + +# 248| [RegExpSequence] ((\S|[\w])*)" +#-----| 0 -> [RegExpGroup] ((\S|[\w])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 248| [RegExpGroup] (\S|[\w]) +#-----| 0 -> [RegExpAlt] \S|[\w] + +# 248| [RegExpStar] (\S|[\w])* +#-----| 0 -> [RegExpGroup] (\S|[\w]) + +# 248| [RegExpCharacterClass] [\w] +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 248| [RegExpCharacterClassEscape] \S + +# 248| [RegExpAlt] \S|[\w] +#-----| 0 -> [RegExpCharacterClassEscape] \S +#-----| 1 -> [RegExpCharacterClass] [\w] + +# 248| [RegExpCharacterClassEscape] \w + +# 252| [RegExpConstant, RegExpNormalChar] " + +# 252| [RegExpGroup] ((1s|[\da-z])*) +#-----| 0 -> [RegExpStar] (1s|[\da-z])* + +# 252| [RegExpSequence] ((1s|[\da-z])*)" +#-----| 0 -> [RegExpGroup] ((1s|[\da-z])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 252| [RegExpGroup] (1s|[\da-z]) +#-----| 0 -> [RegExpAlt] 1s|[\da-z] + +# 252| [RegExpStar] (1s|[\da-z])* +#-----| 0 -> [RegExpGroup] (1s|[\da-z]) + +# 252| [RegExpConstant, RegExpNormalChar] 1s + +# 252| [RegExpAlt] 1s|[\da-z] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 1s +#-----| 1 -> [RegExpCharacterClass] [\da-z] + +# 252| [RegExpCharacterClass] [\da-z] +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpCharacterRange] a-z + +# 252| [RegExpCharacterClassEscape] \d + +# 252| [RegExpConstant, RegExpNormalChar] a + +# 252| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 252| [RegExpConstant, RegExpNormalChar] z + +# 256| [RegExpConstant, RegExpNormalChar] " + +# 256| [RegExpGroup] ((0|[\d])*) +#-----| 0 -> [RegExpStar] (0|[\d])* + +# 256| [RegExpSequence] ((0|[\d])*)" +#-----| 0 -> [RegExpGroup] ((0|[\d])*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 256| [RegExpGroup] (0|[\d]) +#-----| 0 -> [RegExpAlt] 0|[\d] + +# 256| [RegExpStar] (0|[\d])* +#-----| 0 -> [RegExpGroup] (0|[\d]) + +# 256| [RegExpConstant, RegExpNormalChar] 0 + +# 256| [RegExpAlt] 0|[\d] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpCharacterClass] [\d] + +# 256| [RegExpCharacterClass] [\d] +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 256| [RegExpCharacterClassEscape] \d + +# 260| [RegExpConstant, RegExpNormalChar] " + +# 260| [RegExpGroup] (([\d]+)*) +#-----| 0 -> [RegExpStar] ([\d]+)* + +# 260| [RegExpSequence] (([\d]+)*)" +#-----| 0 -> [RegExpGroup] (([\d]+)*) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] " + +# 260| [RegExpGroup] ([\d]+) +#-----| 0 -> [RegExpPlus] [\d]+ + +# 260| [RegExpStar] ([\d]+)* +#-----| 0 -> [RegExpGroup] ([\d]+) + +# 260| [RegExpCharacterClass] [\d] +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 260| [RegExpPlus] [\d]+ +#-----| 0 -> [RegExpCharacterClass] [\d] + +# 260| [RegExpCharacterClassEscape] \d + +# 263| [RegExpGroup] (X\d+) +#-----| 0 -> [RegExpSequence] X\d+ + +# 263| [RegExpOpt] (X\d+)? +#-----| 0 -> [RegExpGroup] (X\d+) + +# 263| [RegExpGroup] (\d+(X\d+)?) +#-----| 0 -> [RegExpSequence] \d+(X\d+)? + +# 263| [RegExpPlus] (\d+(X\d+)?)+ +#-----| 0 -> [RegExpGroup] (\d+(X\d+)?) + +# 263| [RegExpConstant, RegExpNormalChar] X + +# 263| [RegExpSequence] X\d+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpPlus] \d+ + +# 263| [RegExpCharacterClassEscape] \d + +# 263| [RegExpCharacterClassEscape] \d + +# 263| [RegExpPlus] \d+ +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 263| [RegExpPlus] \d+ +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 263| [RegExpSequence] \d+(X\d+)? +#-----| 0 -> [RegExpPlus] \d+ +#-----| 1 -> [RegExpOpt] (X\d+)? + +# 266| [RegExpGroup] (X\d+) +#-----| 0 -> [RegExpSequence] X\d+ + +# 266| [RegExpOpt] (X\d+)? +#-----| 0 -> [RegExpGroup] (X\d+) + +# 266| [RegExpGroup] (\d+(X\d+)?) +#-----| 0 -> [RegExpSequence] \d+(X\d+)? + +# 266| [RegExpPlus] (\d+(X\d+)?)+ +#-----| 0 -> [RegExpGroup] (\d+(X\d+)?) + +# 266| [RegExpConstant, RegExpNormalChar] X + +# 266| [RegExpSequence] X\d+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpPlus] \d+ + +# 266| [RegExpCharacterClassEscape] \d + +# 266| [RegExpCharacterClassEscape] \d + +# 266| [RegExpPlus] \d+ +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 266| [RegExpPlus] \d+ +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 266| [RegExpSequence] \d+(X\d+)? +#-----| 0 -> [RegExpPlus] \d+ +#-----| 1 -> [RegExpOpt] (X\d+)? + +# 269| [RegExpGroup] (X[0-9]*) +#-----| 0 -> [RegExpSequence] X[0-9]* + +# 269| [RegExpOpt] (X[0-9]*)? +#-----| 0 -> [RegExpGroup] (X[0-9]*) + +# 269| [RegExpGroup] ([0-9]+(X[0-9]*)?) +#-----| 0 -> [RegExpSequence] [0-9]+(X[0-9]*)? + +# 269| [RegExpStar] ([0-9]+(X[0-9]*)?)* +#-----| 0 -> [RegExpGroup] ([0-9]+(X[0-9]*)?) + +# 269| [RegExpConstant, RegExpNormalChar] 0 + +# 269| [RegExpConstant, RegExpNormalChar] 0 + +# 269| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 269| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 269| [RegExpConstant, RegExpNormalChar] 9 + +# 269| [RegExpConstant, RegExpNormalChar] 9 + +# 269| [RegExpConstant, RegExpNormalChar] X + +# 269| [RegExpSequence] X[0-9]* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpStar] [0-9]* + +# 269| [RegExpCharacterClass] [0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 269| [RegExpCharacterClass] [0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 269| [RegExpStar] [0-9]* +#-----| 0 -> [RegExpCharacterClass] [0-9] + +# 269| [RegExpPlus] [0-9]+ +#-----| 0 -> [RegExpCharacterClass] [0-9] + +# 269| [RegExpSequence] [0-9]+(X[0-9]*)? +#-----| 0 -> [RegExpPlus] [0-9]+ +#-----| 1 -> [RegExpOpt] (X[0-9]*)? + +# 272| [RegExpGroup] (X[0-9]*) +#-----| 0 -> [RegExpSequence] X[0-9]* + +# 272| [RegExpOpt] (X[0-9]*)? +#-----| 0 -> [RegExpGroup] (X[0-9]*) + +# 272| [RegExpGroup] ([0-9]+(X[0-9]*)?) +#-----| 0 -> [RegExpSequence] [0-9]+(X[0-9]*)? + +# 272| [RegExpStar] ([0-9]+(X[0-9]*)?)* +#-----| 0 -> [RegExpGroup] ([0-9]+(X[0-9]*)?) + +# 272| [RegExpConstant, RegExpNormalChar] 0 + +# 272| [RegExpConstant, RegExpNormalChar] 0 + +# 272| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 272| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 272| [RegExpConstant, RegExpNormalChar] 9 + +# 272| [RegExpConstant, RegExpNormalChar] 9 + +# 272| [RegExpConstant, RegExpNormalChar] X + +# 272| [RegExpSequence] X[0-9]* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpStar] [0-9]* + +# 272| [RegExpCharacterClass] [0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 272| [RegExpCharacterClass] [0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 272| [RegExpStar] [0-9]* +#-----| 0 -> [RegExpCharacterClass] [0-9] + +# 272| [RegExpPlus] [0-9]+ +#-----| 0 -> [RegExpCharacterClass] [0-9] + +# 272| [RegExpSequence] [0-9]+(X[0-9]*)? +#-----| 0 -> [RegExpPlus] [0-9]+ +#-----| 1 -> [RegExpOpt] (X[0-9]*)? + +# 275| [RegExpDollar] $ + +# 275| [RegExpGroup] (>|$) +#-----| 0 -> [RegExpAlt] >|$ + +# 275| [RegExpGroup] ([^>]+) +#-----| 0 -> [RegExpPlus] [^>]+ + +# 275| [RegExpStar] ([^>]+)* +#-----| 0 -> [RegExpGroup] ([^>]+) + +# 275| [RegExpConstant, RegExpNormalChar] > + +# 275| [RegExpConstant, RegExpNormalChar] > + +# 275| [RegExpAlt] >|$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] > +#-----| 1 -> [RegExpDollar] $ + +# 275| [RegExpCharacterClass] [^>] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] > + +# 275| [RegExpPlus] [^>]+ +#-----| 0 -> [RegExpCharacterClass] [^>] + +# 275| [RegExpCaret] ^ + +# 275| [RegExpSequence] ^([^>]+)*(>|$) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpStar] ([^>]+)* +#-----| 2 -> [RegExpGroup] (>|$) + +# 279| [RegExpDollar] $ + +# 279| [RegExpGroup] (>|$) +#-----| 0 -> [RegExpAlt] >|$ + +# 279| [RegExpGroup] ([^>a]+) +#-----| 0 -> [RegExpPlus] [^>a]+ + +# 279| [RegExpStar] ([^>a]+)* +#-----| 0 -> [RegExpGroup] ([^>a]+) + +# 279| [RegExpConstant, RegExpNormalChar] > + +# 279| [RegExpConstant, RegExpNormalChar] > + +# 279| [RegExpAlt] >|$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] > +#-----| 1 -> [RegExpDollar] $ + +# 279| [RegExpCharacterClass] [^>a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] > +#-----| 1 -> [RegExpConstant, RegExpNormalChar] a + +# 279| [RegExpPlus] [^>a]+ +#-----| 0 -> [RegExpCharacterClass] [^>a] + +# 279| [RegExpCaret] ^ + +# 279| [RegExpSequence] ^([^>a]+)*(>|$) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpStar] ([^>a]+)* +#-----| 2 -> [RegExpGroup] (>|$) + +# 279| [RegExpConstant, RegExpNormalChar] a + +# 283| [RegExpDollar] $ + +# 283| [RegExpGroup] (\n\s*) +#-----| 0 -> [RegExpSequence] \n\s* + +# 283| [RegExpPlus] (\n\s*)+ +#-----| 0 -> [RegExpGroup] (\n\s*) + +# 283| [RegExpSequence] (\n\s*)+$ +#-----| 0 -> [RegExpPlus] (\n\s*)+ +#-----| 1 -> [RegExpDollar] $ + +# 283| [RegExpConstant, RegExpEscape] \n + +# 283| [RegExpSequence] \n\s* +#-----| 0 -> [RegExpConstant, RegExpEscape] \n +#-----| 1 -> [RegExpStar] \s* + +# 283| [RegExpCharacterClassEscape] \s + +# 283| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 287| [RegExpConstant, RegExpNormalChar] # + +# 287| [RegExpConstant, RegExpNormalChar] # + +# 287| [RegExpSequence] #.* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] # +#-----| 1 -> [RegExpStar] .* + +# 287| [RegExpGroup] (?:,\d*) +#-----| 0 -> [RegExpSequence] ,\d* + +# 287| [RegExpOpt] (?:,\d*)? +#-----| 0 -> [RegExpGroup] (?:,\d*) + +# 287| [RegExpGroup] (?:[?*+]|\{\d+(?:,\d*)?}) +#-----| 0 -> [RegExpAlt] [?*+]|\{\d+(?:,\d*)?} + +# 287| [RegExpGroup] (?:\s+|#.*|\(\?#[^)]*\)) +#-----| 0 -> [RegExpAlt] \s+|#.*|\(\?#[^)]*\) + +# 287| [RegExpStar] (?:\s+|#.*|\(\?#[^)]*\))* +#-----| 0 -> [RegExpGroup] (?:\s+|#.*|\(\?#[^)]*\)) + +# 287| [RegExpConstant, RegExpNormalChar] ) + +# 287| [RegExpConstant, RegExpNormalChar] * + +# 287| [RegExpConstant, RegExpNormalChar] + + +# 287| [RegExpConstant, RegExpNormalChar] , + +# 287| [RegExpSequence] ,\d* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] , +#-----| 1 -> [RegExpStar] \d* + +# 287| [RegExpDot] . + +# 287| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 287| [RegExpConstant, RegExpNormalChar] ? + +# 287| [RegExpCharacterClass] [?*+] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ? +#-----| 1 -> [RegExpConstant, RegExpNormalChar] * +#-----| 2 -> [RegExpConstant, RegExpNormalChar] + + +# 287| [RegExpAlt] [?*+]|\{\d+(?:,\d*)?} +#-----| 0 -> [RegExpCharacterClass] [?*+] +#-----| 1 -> [RegExpSequence] \{\d+(?:,\d*)?} + +# 287| [RegExpCharacterClass] [^)] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ) + +# 287| [RegExpStar] [^)]* +#-----| 0 -> [RegExpCharacterClass] [^)] + +# 287| [RegExpConstant, RegExpEscape] \( + +# 287| [RegExpSequence] \(\?#[^)]*\) +#-----| 0 -> [RegExpConstant, RegExpEscape] \( +#-----| 1 -> [RegExpConstant, RegExpEscape] \? +#-----| 2 -> [RegExpConstant, RegExpNormalChar] # +#-----| 3 -> [RegExpStar] [^)]* +#-----| 4 -> [RegExpConstant, RegExpEscape] \) + +# 287| [RegExpConstant, RegExpEscape] \) + +# 287| [RegExpConstant, RegExpEscape] \? + +# 287| [RegExpCharacterClassEscape] \d + +# 287| [RegExpCharacterClassEscape] \d + +# 287| [RegExpStar] \d* +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 287| [RegExpPlus] \d+ +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 287| [RegExpCharacterClassEscape] \s + +# 287| [RegExpPlus] \s+ +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 287| [RegExpAlt] \s+|#.*|\(\?#[^)]*\) +#-----| 0 -> [RegExpPlus] \s+ +#-----| 1 -> [RegExpSequence] #.* +#-----| 2 -> [RegExpSequence] \(\?#[^)]*\) + +# 287| [RegExpConstant, RegExpEscape] \{ + +# 287| [RegExpSequence] \{\d+(?:,\d*)?} +#-----| 0 -> [RegExpConstant, RegExpEscape] \{ +#-----| 1 -> [RegExpPlus] \d+ +#-----| 2 -> [RegExpOpt] (?:,\d*)? +#-----| 3 -> [RegExpConstant, RegExpNormalChar] } + +# 287| [RegExpCaret] ^ + +# 287| [RegExpSequence] ^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|\{\d+(?:,\d*)?}) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpStar] (?:\s+|#.*|\(\?#[^)]*\))* +#-----| 2 -> [RegExpGroup] (?:[?*+]|\{\d+(?:,\d*)?}) + +# 287| [RegExpConstant, RegExpNormalChar] } + +# 291| [RegExpConstant, RegExpNormalChar] + +# 291| [RegExpConstant, RegExpNormalChar] + +# 291| [RegExpOpt] ? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] + +# 291| [RegExpGroup] ((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+) +#-----| 0 -> [RegExpPlus] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+ + +# 291| [RegExpStar] ((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)* +#-----| 0 -> [RegExpGroup] ((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+) + +# 291| [RegExpGroup] ([ a-zA-Z{}]+) +#-----| 0 -> [RegExpPlus] [ a-zA-Z{}]+ + +# 291| [RegExpGroup] ([a-zA-Z]+) +#-----| 0 -> [RegExpPlus] [a-zA-Z]+ + +# 291| [RegExpGroup] ([a-zA-Z]+) +#-----| 0 -> [RegExpPlus] [a-zA-Z]+ + +# 291| [RegExpGroup] ([a-zA-Z]+) +#-----| 0 -> [RegExpPlus] [a-zA-Z]+ + +# 291| [RegExpGroup] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?) +#-----| 0 -> [RegExpSequence] \s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),? + +# 291| [RegExpPlus] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+ +#-----| 0 -> [RegExpGroup] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?) + +# 291| [RegExpConstant, RegExpNormalChar] , + +# 291| [RegExpOpt] ,? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] , + +# 291| [RegExpConstant, RegExpNormalChar] A + +# 291| [RegExpConstant, RegExpNormalChar] A + +# 291| [RegExpConstant, RegExpNormalChar] A + +# 291| [RegExpConstant, RegExpNormalChar] A + +# 291| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpCharacterClass] [ a-zA-Z{}] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] +#-----| 1 -> [RegExpCharacterRange] a-z +#-----| 2 -> [RegExpCharacterRange] A-Z +#-----| 3 -> [RegExpConstant, RegExpNormalChar] { +#-----| 4 -> [RegExpConstant, RegExpNormalChar] } + +# 291| [RegExpPlus] [ a-zA-Z{}]+ +#-----| 0 -> [RegExpCharacterClass] [ a-zA-Z{}] + +# 291| [RegExpCharacterClass] [a-zA-Z] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z + +# 291| [RegExpCharacterClass] [a-zA-Z] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z + +# 291| [RegExpCharacterClass] [a-zA-Z] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z + +# 291| [RegExpPlus] [a-zA-Z]+ +#-----| 0 -> [RegExpCharacterClass] [a-zA-Z] + +# 291| [RegExpPlus] [a-zA-Z]+ +#-----| 0 -> [RegExpCharacterClass] [a-zA-Z] + +# 291| [RegExpPlus] [a-zA-Z]+ +#-----| 0 -> [RegExpCharacterClass] [a-zA-Z] + +# 291| [RegExpConstant, RegExpEscape] \( + +# 291| [RegExpConstant, RegExpEscape] \) + +# 291| [RegExpConstant, RegExpEscape] \: + +# 291| [RegExpConstant, RegExpEscape] \[ + +# 291| [RegExpConstant, RegExpEscape] \] + +# 291| [RegExpCharacterClassEscape] \s + +# 291| [RegExpCharacterClassEscape] \s + +# 291| [RegExpCharacterClassEscape] \s + +# 291| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 291| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 291| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 291| [RegExpSequence] \s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),? +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpGroup] ([a-zA-Z]+) +#-----| 2 -> [RegExpConstant, RegExpEscape] \: +#-----| 3 -> [RegExpOpt] ? +#-----| 4 -> [RegExpGroup] ([ a-zA-Z{}]+) +#-----| 5 -> [RegExpOpt] ,? + +# 291| [RegExpConstant, RegExpEscape] \{ + +# 291| [RegExpSequence] \{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\} +#-----| 0 -> [RegExpConstant, RegExpEscape] \{ +#-----| 1 -> [RegExpConstant, RegExpEscape] \[ +#-----| 2 -> [RegExpStar] \s* +#-----| 3 -> [RegExpGroup] ([a-zA-Z]+) +#-----| 4 -> [RegExpConstant, RegExpEscape] \( +#-----| 5 -> [RegExpGroup] ([a-zA-Z]+) +#-----| 6 -> [RegExpConstant, RegExpEscape] \) +#-----| 7 -> [RegExpStar] ((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)* +#-----| 8 -> [RegExpStar] \s* +#-----| 9 -> [RegExpConstant, RegExpEscape] \] +#-----| 10 -> [RegExpConstant, RegExpEscape] \} + +# 291| [RegExpConstant, RegExpEscape] \} + +# 291| [RegExpConstant, RegExpNormalChar] a + +# 291| [RegExpConstant, RegExpNormalChar] a + +# 291| [RegExpConstant, RegExpNormalChar] a + +# 291| [RegExpConstant, RegExpNormalChar] a + +# 291| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 291| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 291| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 291| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 291| [RegExpConstant, RegExpNormalChar] z + +# 291| [RegExpConstant, RegExpNormalChar] z + +# 291| [RegExpConstant, RegExpNormalChar] z + +# 291| [RegExpConstant, RegExpNormalChar] z + +# 291| [RegExpConstant, RegExpNormalChar] { + +# 291| [RegExpConstant, RegExpNormalChar] } + +# 295| [RegExpGroup] (a+|b+|c+) +#-----| 0 -> [RegExpAlt] a+|b+|c+ + +# 295| [RegExpStar] (a+|b+|c+)* +#-----| 0 -> [RegExpGroup] (a+|b+|c+) + +# 295| [RegExpSequence] (a+|b+|c+)*c +#-----| 0 -> [RegExpStar] (a+|b+|c+)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] c + +# 295| [RegExpConstant, RegExpNormalChar] a + +# 295| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 295| [RegExpAlt] a+|b+|c+ +#-----| 0 -> [RegExpPlus] a+ +#-----| 1 -> [RegExpPlus] b+ +#-----| 2 -> [RegExpPlus] c+ + +# 295| [RegExpConstant, RegExpNormalChar] b + +# 295| [RegExpPlus] b+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b + +# 295| [RegExpConstant, RegExpNormalChar] c + +# 295| [RegExpConstant, RegExpNormalChar] c + +# 295| [RegExpPlus] c+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] c + +# 299| [RegExpGroup] (((a+a?)*)+b+) +#-----| 0 -> [RegExpSequence] ((a+a?)*)+b+ + +# 299| [RegExpGroup] ((a+a?)*) +#-----| 0 -> [RegExpStar] (a+a?)* + +# 299| [RegExpPlus] ((a+a?)*)+ +#-----| 0 -> [RegExpGroup] ((a+a?)*) + +# 299| [RegExpSequence] ((a+a?)*)+b+ +#-----| 0 -> [RegExpPlus] ((a+a?)*)+ +#-----| 1 -> [RegExpPlus] b+ + +# 299| [RegExpGroup] (a+a?) +#-----| 0 -> [RegExpSequence] a+a? + +# 299| [RegExpStar] (a+a?)* +#-----| 0 -> [RegExpGroup] (a+a?) + +# 299| [RegExpConstant, RegExpNormalChar] a + +# 299| [RegExpConstant, RegExpNormalChar] a + +# 299| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 299| [RegExpSequence] a+a? +#-----| 0 -> [RegExpPlus] a+ +#-----| 1 -> [RegExpOpt] a? + +# 299| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 299| [RegExpConstant, RegExpNormalChar] b + +# 299| [RegExpPlus] b+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b + +# 303| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 303| [RegExpPlus] (a+)+ +#-----| 0 -> [RegExpGroup] (a+) + +# 303| [RegExpSequence] (a+)+bbbb +#-----| 0 -> [RegExpPlus] (a+)+ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] bbbb + +# 303| [RegExpConstant, RegExpNormalChar] a + +# 303| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 303| [RegExpConstant, RegExpNormalChar] bbbb + +# 306| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 306| [RegExpPlus] (a+)+ +#-----| 0 -> [RegExpGroup] (a+) + +# 306| [RegExpSequence] (a+)+aaaaa*a+ +#-----| 0 -> [RegExpPlus] (a+)+ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] aaaa +#-----| 2 -> [RegExpStar] a* +#-----| 3 -> [RegExpPlus] a+ + +# 306| [RegExpConstant, RegExpNormalChar] a + +# 306| [RegExpConstant, RegExpNormalChar] a + +# 306| [RegExpConstant, RegExpNormalChar] a + +# 306| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 306| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 306| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 306| [RegExpConstant, RegExpNormalChar] aaaa + +# 309| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 309| [RegExpPlus] (a+)+ +#-----| 0 -> [RegExpGroup] (a+) + +# 309| [RegExpSequence] (a+)+aaaaa*a+ +#-----| 0 -> [RegExpPlus] (a+)+ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] aaaa +#-----| 2 -> [RegExpStar] a* +#-----| 3 -> [RegExpPlus] a+ + +# 309| [RegExpConstant, RegExpNormalChar] a + +# 309| [RegExpConstant, RegExpNormalChar] a + +# 309| [RegExpConstant, RegExpNormalChar] a + +# 309| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 309| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 309| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 309| [RegExpConstant, RegExpNormalChar] aaaa + +# 313| [RegExpDollar] $ + +# 313| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 313| [RegExpPlus] (a+)+ +#-----| 0 -> [RegExpGroup] (a+) + +# 313| [RegExpSequence] (a+)+aaaaa$ +#-----| 0 -> [RegExpPlus] (a+)+ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] aaaaa +#-----| 2 -> [RegExpDollar] $ + +# 313| [RegExpConstant, RegExpNormalChar] a + +# 313| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 313| [RegExpConstant, RegExpNormalChar] aaaaa + +# 316| [RegExpGroup] (\n+) +#-----| 0 -> [RegExpPlus] \n+ + +# 316| [RegExpPlus] (\n+)+ +#-----| 0 -> [RegExpGroup] (\n+) + +# 316| [RegExpSequence] (\n+)+\n\n +#-----| 0 -> [RegExpPlus] (\n+)+ +#-----| 1 -> [RegExpConstant, RegExpEscape] \n +#-----| 2 -> [RegExpConstant, RegExpEscape] \n + +# 316| [RegExpConstant, RegExpEscape] \n + +# 316| [RegExpConstant, RegExpEscape] \n + +# 316| [RegExpConstant, RegExpEscape] \n + +# 316| [RegExpPlus] \n+ +#-----| 0 -> [RegExpConstant, RegExpEscape] \n + +# 319| [RegExpGroup] (\n+) +#-----| 0 -> [RegExpPlus] \n+ + +# 319| [RegExpPlus] (\n+)+ +#-----| 0 -> [RegExpGroup] (\n+) + +# 319| [RegExpSequence] (\n+)+\n\n +#-----| 0 -> [RegExpPlus] (\n+)+ +#-----| 1 -> [RegExpConstant, RegExpEscape] \n +#-----| 2 -> [RegExpConstant, RegExpEscape] \n + +# 319| [RegExpConstant, RegExpEscape] \n + +# 319| [RegExpConstant, RegExpEscape] \n + +# 319| [RegExpConstant, RegExpEscape] \n + +# 319| [RegExpPlus] \n+ +#-----| 0 -> [RegExpConstant, RegExpEscape] \n + +# 323| [RegExpDollar] $ + +# 323| [RegExpGroup] (\n+) +#-----| 0 -> [RegExpPlus] \n+ + +# 323| [RegExpPlus] (\n+)+ +#-----| 0 -> [RegExpGroup] (\n+) + +# 323| [RegExpSequence] (\n+)+\n\n$ +#-----| 0 -> [RegExpPlus] (\n+)+ +#-----| 1 -> [RegExpConstant, RegExpEscape] \n +#-----| 2 -> [RegExpConstant, RegExpEscape] \n +#-----| 3 -> [RegExpDollar] $ + +# 323| [RegExpConstant, RegExpEscape] \n + +# 323| [RegExpConstant, RegExpEscape] \n + +# 323| [RegExpConstant, RegExpEscape] \n + +# 323| [RegExpPlus] \n+ +#-----| 0 -> [RegExpConstant, RegExpEscape] \n + +# 327| [RegExpDollar] $ + +# 327| [RegExpGroup] ([^X]+) +#-----| 0 -> [RegExpPlus] [^X]+ + +# 327| [RegExpStar] ([^X]+)* +#-----| 0 -> [RegExpGroup] ([^X]+) + +# 327| [RegExpSequence] ([^X]+)*$ +#-----| 0 -> [RegExpStar] ([^X]+)* +#-----| 1 -> [RegExpDollar] $ + +# 327| [RegExpConstant, RegExpNormalChar] X + +# 327| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + +# 327| [RegExpPlus] [^X]+ +#-----| 0 -> [RegExpCharacterClass] [^X] + +# 331| [RegExpDollar] $ + +# 331| [RegExpGroup] (([^X]b)+) +#-----| 0 -> [RegExpPlus] ([^X]b)+ + +# 331| [RegExpStar] (([^X]b)+)* +#-----| 0 -> [RegExpGroup] (([^X]b)+) + +# 331| [RegExpSequence] (([^X]b)+)*$ +#-----| 0 -> [RegExpStar] (([^X]b)+)* +#-----| 1 -> [RegExpDollar] $ + +# 331| [RegExpGroup] ([^X]b) +#-----| 0 -> [RegExpSequence] [^X]b + +# 331| [RegExpPlus] ([^X]b)+ +#-----| 0 -> [RegExpGroup] ([^X]b) + +# 331| [RegExpConstant, RegExpNormalChar] X + +# 331| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + +# 331| [RegExpSequence] [^X]b +#-----| 0 -> [RegExpCharacterClass] [^X] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 331| [RegExpConstant, RegExpNormalChar] b + +# 334| [RegExpDollar] $ + +# 334| [RegExpAlt] $|[^X]b +#-----| 0 -> [RegExpDollar] $ +#-----| 1 -> [RegExpSequence] [^X]b + +# 334| [RegExpGroup] ($|[^X]b) +#-----| 0 -> [RegExpAlt] $|[^X]b + +# 334| [RegExpGroup] (([^X]b)+) +#-----| 0 -> [RegExpPlus] ([^X]b)+ + +# 334| [RegExpStar] (([^X]b)+)* +#-----| 0 -> [RegExpGroup] (([^X]b)+) + +# 334| [RegExpSequence] (([^X]b)+)*($|[^X]b) +#-----| 0 -> [RegExpStar] (([^X]b)+)* +#-----| 1 -> [RegExpGroup] ($|[^X]b) + +# 334| [RegExpGroup] ([^X]b) +#-----| 0 -> [RegExpSequence] [^X]b + +# 334| [RegExpPlus] ([^X]b)+ +#-----| 0 -> [RegExpGroup] ([^X]b) + +# 334| [RegExpConstant, RegExpNormalChar] X + +# 334| [RegExpConstant, RegExpNormalChar] X + +# 334| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + +# 334| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + +# 334| [RegExpSequence] [^X]b +#-----| 0 -> [RegExpCharacterClass] [^X] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 334| [RegExpSequence] [^X]b +#-----| 0 -> [RegExpCharacterClass] [^X] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 334| [RegExpConstant, RegExpNormalChar] b + +# 334| [RegExpConstant, RegExpNormalChar] b + +# 337| [RegExpDollar] $ + +# 337| [RegExpAlt] $|[^X]b +#-----| 0 -> [RegExpDollar] $ +#-----| 1 -> [RegExpSequence] [^X]b + +# 337| [RegExpGroup] ($|[^X]b) +#-----| 0 -> [RegExpAlt] $|[^X]b + +# 337| [RegExpGroup] (([^X]b)+) +#-----| 0 -> [RegExpPlus] ([^X]b)+ + +# 337| [RegExpStar] (([^X]b)+)* +#-----| 0 -> [RegExpGroup] (([^X]b)+) + +# 337| [RegExpSequence] (([^X]b)+)*($|[^X]b) +#-----| 0 -> [RegExpStar] (([^X]b)+)* +#-----| 1 -> [RegExpGroup] ($|[^X]b) + +# 337| [RegExpGroup] ([^X]b) +#-----| 0 -> [RegExpSequence] [^X]b + +# 337| [RegExpPlus] ([^X]b)+ +#-----| 0 -> [RegExpGroup] ([^X]b) + +# 337| [RegExpConstant, RegExpNormalChar] X + +# 337| [RegExpConstant, RegExpNormalChar] X + +# 337| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + +# 337| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + +# 337| [RegExpSequence] [^X]b +#-----| 0 -> [RegExpCharacterClass] [^X] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 337| [RegExpSequence] [^X]b +#-----| 0 -> [RegExpCharacterClass] [^X] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 337| [RegExpConstant, RegExpNormalChar] b + +# 337| [RegExpConstant, RegExpNormalChar] b + +# 341| [RegExpDollar] $ + +# 341| [RegExpAlt] $|[^X]c +#-----| 0 -> [RegExpDollar] $ +#-----| 1 -> [RegExpSequence] [^X]c + +# 341| [RegExpGroup] ($|[^X]c) +#-----| 0 -> [RegExpAlt] $|[^X]c + +# 341| [RegExpGroup] (([^X]b)+) +#-----| 0 -> [RegExpPlus] ([^X]b)+ + +# 341| [RegExpStar] (([^X]b)+)* +#-----| 0 -> [RegExpGroup] (([^X]b)+) + +# 341| [RegExpSequence] (([^X]b)+)*($|[^X]c) +#-----| 0 -> [RegExpStar] (([^X]b)+)* +#-----| 1 -> [RegExpGroup] ($|[^X]c) + +# 341| [RegExpGroup] ([^X]b) +#-----| 0 -> [RegExpSequence] [^X]b + +# 341| [RegExpPlus] ([^X]b)+ +#-----| 0 -> [RegExpGroup] ([^X]b) + +# 341| [RegExpConstant, RegExpNormalChar] X + +# 341| [RegExpConstant, RegExpNormalChar] X + +# 341| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + +# 341| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + +# 341| [RegExpSequence] [^X]b +#-----| 0 -> [RegExpCharacterClass] [^X] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 341| [RegExpSequence] [^X]c +#-----| 0 -> [RegExpCharacterClass] [^X] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] c + +# 341| [RegExpConstant, RegExpNormalChar] b + +# 341| [RegExpConstant, RegExpNormalChar] c + +# 344| [RegExpGroup] ((ab)+) +#-----| 0 -> [RegExpPlus] (ab)+ + +# 344| [RegExpStar] ((ab)+)* +#-----| 0 -> [RegExpGroup] ((ab)+) + +# 344| [RegExpSequence] ((ab)+)*ababab +#-----| 0 -> [RegExpStar] ((ab)+)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] ababab + +# 344| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 344| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 344| [RegExpConstant, RegExpNormalChar] ab + +# 344| [RegExpConstant, RegExpNormalChar] ababab + +# 347| [RegExpGroup] ((ab)+) +#-----| 0 -> [RegExpPlus] (ab)+ + +# 347| [RegExpStar] ((ab)+)* +#-----| 0 -> [RegExpGroup] ((ab)+) + +# 347| [RegExpSequence] ((ab)+)*ababab +#-----| 0 -> [RegExpStar] ((ab)+)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] ababab + +# 347| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 347| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 347| [RegExpConstant, RegExpNormalChar] ab + +# 347| [RegExpConstant, RegExpNormalChar] ababab + +# 350| [RegExpGroup] ((ab)+) +#-----| 0 -> [RegExpPlus] (ab)+ + +# 350| [RegExpStar] ((ab)+)* +#-----| 0 -> [RegExpGroup] ((ab)+) + +# 350| [RegExpSequence] ((ab)+)*abab(ab)*(ab)+ +#-----| 0 -> [RegExpStar] ((ab)+)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] abab +#-----| 2 -> [RegExpStar] (ab)* +#-----| 3 -> [RegExpPlus] (ab)+ + +# 350| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 350| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 350| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 350| [RegExpStar] (ab)* +#-----| 0 -> [RegExpGroup] (ab) + +# 350| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 350| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 350| [RegExpConstant, RegExpNormalChar] ab + +# 350| [RegExpConstant, RegExpNormalChar] ab + +# 350| [RegExpConstant, RegExpNormalChar] ab + +# 350| [RegExpConstant, RegExpNormalChar] abab + +# 353| [RegExpGroup] ((ab)+) +#-----| 0 -> [RegExpPlus] (ab)+ + +# 353| [RegExpStar] ((ab)+)* +#-----| 0 -> [RegExpGroup] ((ab)+) + +# 353| [RegExpSequence] ((ab)+)*abab(ab)*(ab)+ +#-----| 0 -> [RegExpStar] ((ab)+)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] abab +#-----| 2 -> [RegExpStar] (ab)* +#-----| 3 -> [RegExpPlus] (ab)+ + +# 353| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 353| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 353| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 353| [RegExpStar] (ab)* +#-----| 0 -> [RegExpGroup] (ab) + +# 353| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 353| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 353| [RegExpConstant, RegExpNormalChar] ab + +# 353| [RegExpConstant, RegExpNormalChar] ab + +# 353| [RegExpConstant, RegExpNormalChar] ab + +# 353| [RegExpConstant, RegExpNormalChar] abab + +# 356| [RegExpGroup] ((ab)+) +#-----| 0 -> [RegExpPlus] (ab)+ + +# 356| [RegExpStar] ((ab)+)* +#-----| 0 -> [RegExpGroup] ((ab)+) + +# 356| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 356| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 356| [RegExpConstant, RegExpNormalChar] ab + +# 359| [RegExpGroup] ((ab)+) +#-----| 0 -> [RegExpPlus] (ab)+ + +# 359| [RegExpStar] ((ab)+)* +#-----| 0 -> [RegExpGroup] ((ab)+) + +# 359| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 359| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 359| [RegExpConstant, RegExpNormalChar] ab + +# 363| [RegExpDollar] $ + +# 363| [RegExpGroup] ((ab)+) +#-----| 0 -> [RegExpPlus] (ab)+ + +# 363| [RegExpStar] ((ab)+)* +#-----| 0 -> [RegExpGroup] ((ab)+) + +# 363| [RegExpSequence] ((ab)+)*$ +#-----| 0 -> [RegExpStar] ((ab)+)* +#-----| 1 -> [RegExpDollar] $ + +# 363| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 363| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 363| [RegExpConstant, RegExpNormalChar] ab + +# 366| [RegExpGroup] ((ab)+) +#-----| 0 -> [RegExpPlus] (ab)+ + +# 366| [RegExpStar] ((ab)+)* +#-----| 0 -> [RegExpGroup] ((ab)+) + +# 366| [RegExpSequence] ((ab)+)*[a1][b1][a2][b2][a3][b3] +#-----| 0 -> [RegExpStar] ((ab)+)* +#-----| 1 -> [RegExpCharacterClass] [a1] +#-----| 2 -> [RegExpCharacterClass] [b1] +#-----| 3 -> [RegExpCharacterClass] [a2] +#-----| 4 -> [RegExpCharacterClass] [b2] +#-----| 5 -> [RegExpCharacterClass] [a3] +#-----| 6 -> [RegExpCharacterClass] [b3] + +# 366| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 366| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 366| [RegExpConstant, RegExpNormalChar] 1 + +# 366| [RegExpConstant, RegExpNormalChar] 1 + +# 366| [RegExpConstant, RegExpNormalChar] 2 + +# 366| [RegExpConstant, RegExpNormalChar] 2 + +# 366| [RegExpConstant, RegExpNormalChar] 3 + +# 366| [RegExpConstant, RegExpNormalChar] 3 + +# 366| [RegExpCharacterClass] [a1] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 366| [RegExpCharacterClass] [a2] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 + +# 366| [RegExpCharacterClass] [a3] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 3 + +# 366| [RegExpCharacterClass] [b1] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 366| [RegExpCharacterClass] [b2] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 + +# 366| [RegExpCharacterClass] [b3] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 3 + +# 366| [RegExpConstant, RegExpNormalChar] a + +# 366| [RegExpConstant, RegExpNormalChar] a + +# 366| [RegExpConstant, RegExpNormalChar] a + +# 366| [RegExpConstant, RegExpNormalChar] ab + +# 366| [RegExpConstant, RegExpNormalChar] b + +# 366| [RegExpConstant, RegExpNormalChar] b + +# 366| [RegExpConstant, RegExpNormalChar] b + +# 369| [RegExpGroup] ((ab)+) +#-----| 0 -> [RegExpPlus] (ab)+ + +# 369| [RegExpStar] ((ab)+)* +#-----| 0 -> [RegExpGroup] ((ab)+) + +# 369| [RegExpSequence] ((ab)+)*[a1][b1][a2][b2][a3][b3] +#-----| 0 -> [RegExpStar] ((ab)+)* +#-----| 1 -> [RegExpCharacterClass] [a1] +#-----| 2 -> [RegExpCharacterClass] [b1] +#-----| 3 -> [RegExpCharacterClass] [a2] +#-----| 4 -> [RegExpCharacterClass] [b2] +#-----| 5 -> [RegExpCharacterClass] [a3] +#-----| 6 -> [RegExpCharacterClass] [b3] + +# 369| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 369| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 369| [RegExpConstant, RegExpNormalChar] 1 + +# 369| [RegExpConstant, RegExpNormalChar] 1 + +# 369| [RegExpConstant, RegExpNormalChar] 2 + +# 369| [RegExpConstant, RegExpNormalChar] 2 + +# 369| [RegExpConstant, RegExpNormalChar] 3 + +# 369| [RegExpConstant, RegExpNormalChar] 3 + +# 369| [RegExpCharacterClass] [a1] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 369| [RegExpCharacterClass] [a2] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 + +# 369| [RegExpCharacterClass] [a3] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 3 + +# 369| [RegExpCharacterClass] [b1] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 369| [RegExpCharacterClass] [b2] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 + +# 369| [RegExpCharacterClass] [b3] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 3 + +# 369| [RegExpConstant, RegExpNormalChar] a + +# 369| [RegExpConstant, RegExpNormalChar] a + +# 369| [RegExpConstant, RegExpNormalChar] a + +# 369| [RegExpConstant, RegExpNormalChar] ab + +# 369| [RegExpConstant, RegExpNormalChar] b + +# 369| [RegExpConstant, RegExpNormalChar] b + +# 369| [RegExpConstant, RegExpNormalChar] b + +# 373| [RegExpGroup] (.) +#-----| 0 -> [RegExpDot] . + +# 373| [RegExpGroup] ([\n\s]+) +#-----| 0 -> [RegExpPlus] [\n\s]+ + +# 373| [RegExpStar] ([\n\s]+)* +#-----| 0 -> [RegExpGroup] ([\n\s]+) + +# 373| [RegExpSequence] ([\n\s]+)*(.) +#-----| 0 -> [RegExpStar] ([\n\s]+)* +#-----| 1 -> [RegExpGroup] (.) + +# 373| [RegExpDot] . + +# 373| [RegExpCharacterClass] [\n\s] +#-----| 0 -> [RegExpConstant, RegExpEscape] \n +#-----| 1 -> [RegExpCharacterClassEscape] \s + +# 373| [RegExpPlus] [\n\s]+ +#-----| 0 -> [RegExpCharacterClass] [\n\s] + +# 373| [RegExpConstant, RegExpEscape] \n + +# 373| [RegExpCharacterClassEscape] \s + +# 376| [RegExpGroup] (A*A*X) +#-----| 0 -> [RegExpSequence] A*A*X + +# 376| [RegExpStar] (A*A*X)* +#-----| 0 -> [RegExpGroup] (A*A*X) + +# 376| [RegExpConstant, RegExpNormalChar] A + +# 376| [RegExpConstant, RegExpNormalChar] A + +# 376| [RegExpStar] A* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A + +# 376| [RegExpStar] A* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A + +# 376| [RegExpSequence] A*A*X +#-----| 0 -> [RegExpStar] A* +#-----| 1 -> [RegExpStar] A* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] X + +# 376| [RegExpConstant, RegExpNormalChar] X + +# 379| [RegExpGroup] ([^\\\]]+) +#-----| 0 -> [RegExpPlus] [^\\\]]+ + +# 379| [RegExpStar] ([^\\\]]+)* +#-----| 0 -> [RegExpGroup] ([^\\\]]+) + +# 379| [RegExpCharacterClass] [^\\\]] +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpEscape] \] + +# 379| [RegExpPlus] [^\\\]]+ +#-----| 0 -> [RegExpCharacterClass] [^\\\]] + +# 379| [RegExpConstant, RegExpEscape] \\ + +# 379| [RegExpConstant, RegExpEscape] \] + +# 392| [RegExpGroup] (b+) +#-----| 0 -> [RegExpPlus] b+ + +# 392| [RegExpPlus] (b+)+ +#-----| 0 -> [RegExpGroup] (b+) + +# 392| [RegExpConstant, RegExpNormalChar] X + +# 392| [RegExpConstant, RegExpNormalChar] a + +# 392| [RegExpRange] a{2,3} +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 392| [RegExpSequence] a{2,3}(b+)+X +#-----| 0 -> [RegExpRange] a{2,3} +#-----| 1 -> [RegExpPlus] (b+)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] X + +# 392| [RegExpConstant, RegExpNormalChar] b + +# 392| [RegExpPlus] b+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b + +# 396| [RegExpConstant, RegExpNormalChar] " + +# 396| [RegExpConstant, RegExpNormalChar] " + +# 396| [RegExpConstant, RegExpNormalChar] " + +# 396| [RegExpSequence] "[^"]*" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpStar] [^"]* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 396| [RegExpConstant, RegExpNormalChar] ' + +# 396| [RegExpConstant, RegExpNormalChar] ' + +# 396| [RegExpConstant, RegExpNormalChar] ' + +# 396| [RegExpSequence] '[^']*' +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ' +#-----| 1 -> [RegExpStar] [^']* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] ' + +# 396| [RegExpGroup] ((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*) +#-----| 0 -> [RegExpStar] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)* + +# 396| [RegExpGroup] (?:"[^"]*") +#-----| 0 -> [RegExpSequence] "[^"]*" + +# 396| [RegExpAlt] (?:"[^"]*")|(?:'[^']*')|[^>\s]+ +#-----| 0 -> [RegExpGroup] (?:"[^"]*") +#-----| 1 -> [RegExpGroup] (?:'[^']*') +#-----| 2 -> [RegExpPlus] [^>\s]+ + +# 396| [RegExpGroup] (?:'[^']*') +#-----| 0 -> [RegExpSequence] '[^']*' + +# 396| [RegExpGroup] (?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) +#-----| 0 -> [RegExpAlt] (?:"[^"]*")|(?:'[^']*')|[^>\s]+ + +# 396| [RegExpGroup] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+)) +#-----| 0 -> [RegExpSequence] \s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) + +# 396| [RegExpOpt] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? +#-----| 0 -> [RegExpGroup] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+)) + +# 396| [RegExpGroup] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?) +#-----| 0 -> [RegExpSequence] \s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? + +# 396| [RegExpStar] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)* +#-----| 0 -> [RegExpGroup] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?) + +# 396| [RegExpGroup] (\/?) +#-----| 0 -> [RegExpOpt] \/? + +# 396| [RegExpGroup] (\w+) +#-----| 0 -> [RegExpPlus] \w+ + +# 396| [RegExpConstant, RegExpNormalChar] < + +# 396| [RegExpConstant, RegExpNormalChar] = + +# 396| [RegExpConstant, RegExpNormalChar] > + +# 396| [RegExpConstant, RegExpNormalChar] > + +# 396| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " + +# 396| [RegExpStar] [^"]* +#-----| 0 -> [RegExpCharacterClass] [^"] + +# 396| [RegExpCharacterClass] [^'] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ' + +# 396| [RegExpStar] [^']* +#-----| 0 -> [RegExpCharacterClass] [^'] + +# 396| [RegExpCharacterClass] [^>\s] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] > +#-----| 1 -> [RegExpCharacterClassEscape] \s + +# 396| [RegExpPlus] [^>\s]+ +#-----| 0 -> [RegExpCharacterClass] [^>\s] + +# 396| [RegExpConstant, RegExpEscape] \/ + +# 396| [RegExpOpt] \/? +#-----| 0 -> [RegExpConstant, RegExpEscape] \/ + +# 396| [RegExpCharacterClassEscape] \s + +# 396| [RegExpCharacterClassEscape] \s + +# 396| [RegExpCharacterClassEscape] \s + +# 396| [RegExpCharacterClassEscape] \s + +# 396| [RegExpCharacterClassEscape] \s + +# 396| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 396| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 396| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 396| [RegExpSequence] \s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] = +#-----| 2 -> [RegExpStar] \s* +#-----| 3 -> [RegExpGroup] (?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) + +# 396| [RegExpPlus] \s+ +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 396| [RegExpSequence] \s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? +#-----| 0 -> [RegExpPlus] \s+ +#-----| 1 -> [RegExpPlus] \w+ +#-----| 2 -> [RegExpOpt] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? + +# 396| [RegExpCharacterClassEscape] \w + +# 396| [RegExpCharacterClassEscape] \w + +# 396| [RegExpPlus] \w+ +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 396| [RegExpPlus] \w+ +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 396| [RegExpCaret] ^ + +# 396| [RegExpSequence] ^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)> +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] < +#-----| 2 -> [RegExpGroup] (\w+) +#-----| 3 -> [RegExpGroup] ((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*) +#-----| 4 -> [RegExpStar] \s* +#-----| 5 -> [RegExpGroup] (\/?) +#-----| 6 -> [RegExpConstant, RegExpNormalChar] > + +# 399| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 399| [RegExpStar] (a+)* +#-----| 0 -> [RegExpGroup] (a+) + +# 399| [RegExpSequence] (a+)*[\s\S][\s\S][\s\S]? +#-----| 0 -> [RegExpStar] (a+)* +#-----| 1 -> [RegExpCharacterClass] [\s\S] +#-----| 2 -> [RegExpCharacterClass] [\s\S] +#-----| 3 -> [RegExpOpt] [\s\S]? + +# 399| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 399| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 399| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 399| [RegExpOpt] [\s\S]? +#-----| 0 -> [RegExpCharacterClass] [\s\S] + +# 399| [RegExpCharacterClassEscape] \S + +# 399| [RegExpCharacterClassEscape] \S + +# 399| [RegExpCharacterClassEscape] \S + +# 399| [RegExpCharacterClassEscape] \s + +# 399| [RegExpCharacterClassEscape] \s + +# 399| [RegExpCharacterClassEscape] \s + +# 399| [RegExpConstant, RegExpNormalChar] a + +# 399| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 402| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 402| [RegExpStar] (a+)* +#-----| 0 -> [RegExpGroup] (a+) + +# 402| [RegExpSequence] (a+)*[\s\S]{2,3} +#-----| 0 -> [RegExpStar] (a+)* +#-----| 1 -> [RegExpRange] [\s\S]{2,3} + +# 402| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 402| [RegExpRange] [\s\S]{2,3} +#-----| 0 -> [RegExpCharacterClass] [\s\S] + +# 402| [RegExpCharacterClassEscape] \S + +# 402| [RegExpCharacterClassEscape] \s + +# 402| [RegExpConstant, RegExpNormalChar] a + +# 402| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 405| [RegExpDollar] $ + +# 405| [RegExpGroup] ([\s\S]{2,}|X) +#-----| 0 -> [RegExpAlt] [\s\S]{2,}|X + +# 405| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 405| [RegExpStar] (a+)* +#-----| 0 -> [RegExpGroup] (a+) + +# 405| [RegExpSequence] (a+)*([\s\S]{2,}|X)$ +#-----| 0 -> [RegExpStar] (a+)* +#-----| 1 -> [RegExpGroup] ([\s\S]{2,}|X) +#-----| 2 -> [RegExpDollar] $ + +# 405| [RegExpConstant, RegExpNormalChar] X + +# 405| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 405| [InfiniteRepetitionQuantifier, RegExpRange] [\s\S]{2,} +#-----| 0 -> [RegExpCharacterClass] [\s\S] + +# 405| [RegExpAlt] [\s\S]{2,}|X +#-----| 0 -> [InfiniteRepetitionQuantifier, RegExpRange] [\s\S]{2,} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] X + +# 405| [RegExpCharacterClassEscape] \S + +# 405| [RegExpCharacterClassEscape] \s + +# 405| [RegExpConstant, RegExpNormalChar] a + +# 405| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 408| [RegExpDollar] $ + +# 408| [RegExpGroup] ([\s\S]*|X) +#-----| 0 -> [RegExpAlt] [\s\S]*|X + +# 408| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 408| [RegExpStar] (a+)* +#-----| 0 -> [RegExpGroup] (a+) + +# 408| [RegExpSequence] (a+)*([\s\S]*|X)$ +#-----| 0 -> [RegExpStar] (a+)* +#-----| 1 -> [RegExpGroup] ([\s\S]*|X) +#-----| 2 -> [RegExpDollar] $ + +# 408| [RegExpConstant, RegExpNormalChar] X + +# 408| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 408| [RegExpStar] [\s\S]* +#-----| 0 -> [RegExpCharacterClass] [\s\S] + +# 408| [RegExpAlt] [\s\S]*|X +#-----| 0 -> [RegExpStar] [\s\S]* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] X + +# 408| [RegExpCharacterClassEscape] \S + +# 408| [RegExpCharacterClassEscape] \s + +# 408| [RegExpConstant, RegExpNormalChar] a + +# 408| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 412| [RegExpDollar] $ + +# 412| [RegExpGroup] ((a+)*$|[\s\S]+) +#-----| 0 -> [RegExpAlt] (a+)*$|[\s\S]+ + +# 412| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 412| [RegExpStar] (a+)* +#-----| 0 -> [RegExpGroup] (a+) + +# 412| [RegExpSequence] (a+)*$ +#-----| 0 -> [RegExpStar] (a+)* +#-----| 1 -> [RegExpDollar] $ + +# 412| [RegExpAlt] (a+)*$|[\s\S]+ +#-----| 0 -> [RegExpSequence] (a+)*$ +#-----| 1 -> [RegExpPlus] [\s\S]+ + +# 412| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 412| [RegExpPlus] [\s\S]+ +#-----| 0 -> [RegExpCharacterClass] [\s\S] + +# 412| [RegExpCharacterClassEscape] \S + +# 412| [RegExpCharacterClassEscape] \s + +# 412| [RegExpConstant, RegExpNormalChar] a + +# 412| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 415| [RegExpDollar] $ + +# 415| [RegExpGroup] ([\s\S]+|(a+)*$) +#-----| 0 -> [RegExpAlt] [\s\S]+|(a+)*$ + +# 415| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 415| [RegExpStar] (a+)* +#-----| 0 -> [RegExpGroup] (a+) + +# 415| [RegExpSequence] (a+)*$ +#-----| 0 -> [RegExpStar] (a+)* +#-----| 1 -> [RegExpDollar] $ + +# 415| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 415| [RegExpPlus] [\s\S]+ +#-----| 0 -> [RegExpCharacterClass] [\s\S] + +# 415| [RegExpAlt] [\s\S]+|(a+)*$ +#-----| 0 -> [RegExpPlus] [\s\S]+ +#-----| 1 -> [RegExpSequence] (a+)*$ + +# 415| [RegExpCharacterClassEscape] \S + +# 415| [RegExpCharacterClassEscape] \s + +# 415| [RegExpConstant, RegExpNormalChar] a + +# 415| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 418| [RegExpDollar] $ + +# 418| [RegExpGroup] ((;|^)a+) +#-----| 0 -> [RegExpSequence] (;|^)a+ + +# 418| [RegExpPlus] ((;|^)a+)+ +#-----| 0 -> [RegExpGroup] ((;|^)a+) + +# 418| [RegExpSequence] ((;|^)a+)+$ +#-----| 0 -> [RegExpPlus] ((;|^)a+)+ +#-----| 1 -> [RegExpDollar] $ + +# 418| [RegExpGroup] (;|^) +#-----| 0 -> [RegExpAlt] ;|^ + +# 418| [RegExpSequence] (;|^)a+ +#-----| 0 -> [RegExpGroup] (;|^) +#-----| 1 -> [RegExpPlus] a+ + +# 418| [RegExpConstant, RegExpNormalChar] ; + +# 418| [RegExpAlt] ;|^ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ; +#-----| 1 -> [RegExpCaret] ^ + +# 418| [RegExpCaret] ^ + +# 418| [RegExpConstant, RegExpNormalChar] a + +# 418| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpGroup] (^|;) +#-----| 0 -> [RegExpAlt] ^|; + +# 422| [RegExpSequence] (^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f +#-----| 0 -> [RegExpGroup] (^|;) +#-----| 1 -> [RegExpGroup] (0|1) +#-----| 2 -> [RegExpGroup] (0|1) +#-----| 3 -> [RegExpGroup] (0|1) +#-----| 4 -> [RegExpGroup] (0|1) +#-----| 5 -> [RegExpGroup] (0|1) +#-----| 6 -> [RegExpGroup] (0|1) +#-----| 7 -> [RegExpGroup] (0|1) +#-----| 8 -> [RegExpGroup] (0|1) +#-----| 9 -> [RegExpGroup] (0|1) +#-----| 10 -> [RegExpGroup] (0|1) +#-----| 11 -> [RegExpGroup] (0|1) +#-----| 12 -> [RegExpGroup] (0|1) +#-----| 13 -> [RegExpGroup] (0|1) +#-----| 14 -> [RegExpGroup] (0|1) +#-----| 15 -> [RegExpPlus] (e+)+ +#-----| 16 -> [RegExpConstant, RegExpNormalChar] f + +# 422| [RegExpGroup] (e+) +#-----| 0 -> [RegExpPlus] e+ + +# 422| [RegExpPlus] (e+)+ +#-----| 0 -> [RegExpGroup] (e+) + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] ; + +# 422| [RegExpCaret] ^ + +# 422| [RegExpAlt] ^|; +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] ; + +# 422| [RegExpConstant, RegExpNormalChar] e + +# 422| [RegExpPlus] e+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] e + +# 422| [RegExpConstant, RegExpNormalChar] f + +# 426| [RegExpDollar] $ + +# 426| [RegExpGroup] (c+) +#-----| 0 -> [RegExpPlus] c+ + +# 426| [RegExpPlus] (c+)+ +#-----| 0 -> [RegExpGroup] (c+) + +# 426| [RegExpCaret] ^ + +# 426| [RegExpSequence] ^ab(c+)+$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] ab +#-----| 2 -> [RegExpPlus] (c+)+ +#-----| 3 -> [RegExpDollar] $ + +# 426| [RegExpConstant, RegExpNormalChar] ab + +# 426| [RegExpConstant, RegExpNormalChar] c + +# 426| [RegExpPlus] c+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] c + +# 430| [RegExpGroup] (\d(\s+)*) +#-----| 0 -> [RegExpSequence] \d(\s+)* + +# 430| [RegExpRange] (\d(\s+)*){20} +#-----| 0 -> [RegExpGroup] (\d(\s+)*) + +# 430| [RegExpGroup] (\s+) +#-----| 0 -> [RegExpPlus] \s+ + +# 430| [RegExpStar] (\s+)* +#-----| 0 -> [RegExpGroup] (\s+) + +# 430| [RegExpCharacterClassEscape] \d + +# 430| [RegExpSequence] \d(\s+)* +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpStar] (\s+)* + +# 430| [RegExpCharacterClassEscape] \s + +# 430| [RegExpPlus] \s+ +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 433| [RegExpDollar] $ + +# 433| [RegExpGroup] (([^/]|X)+) +#-----| 0 -> [RegExpPlus] ([^/]|X)+ + +# 433| [RegExpSequence] (([^/]|X)+)(\/[\s\S]*)*$ +#-----| 0 -> [RegExpGroup] (([^/]|X)+) +#-----| 1 -> [RegExpStar] (\/[\s\S]*)* +#-----| 2 -> [RegExpDollar] $ + +# 433| [RegExpGroup] ([^/]|X) +#-----| 0 -> [RegExpAlt] [^/]|X + +# 433| [RegExpPlus] ([^/]|X)+ +#-----| 0 -> [RegExpGroup] ([^/]|X) + +# 433| [RegExpGroup] (\/[\s\S]*) +#-----| 0 -> [RegExpSequence] \/[\s\S]* + +# 433| [RegExpStar] (\/[\s\S]*)* +#-----| 0 -> [RegExpGroup] (\/[\s\S]*) + +# 433| [RegExpConstant, RegExpNormalChar] / + +# 433| [RegExpConstant, RegExpNormalChar] X + +# 433| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 433| [RegExpStar] [\s\S]* +#-----| 0 -> [RegExpCharacterClass] [\s\S] + +# 433| [RegExpCharacterClass] [^/] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] / + +# 433| [RegExpAlt] [^/]|X +#-----| 0 -> [RegExpCharacterClass] [^/] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] X + +# 433| [RegExpConstant, RegExpEscape] \/ + +# 433| [RegExpSequence] \/[\s\S]* +#-----| 0 -> [RegExpConstant, RegExpEscape] \/ +#-----| 1 -> [RegExpStar] [\s\S]* + +# 433| [RegExpCharacterClassEscape] \S + +# 433| [RegExpCharacterClassEscape] \s + +# 436| [RegExpDollar] $ + +# 436| [RegExpGroup] ((x([^Y]+)?)*(Y|$)) +#-----| 0 -> [RegExpSequence] (x([^Y]+)?)*(Y|$) + +# 436| [RegExpGroup] (Y|$) +#-----| 0 -> [RegExpAlt] Y|$ + +# 436| [RegExpGroup] ([^Y]+) +#-----| 0 -> [RegExpPlus] [^Y]+ + +# 436| [RegExpOpt] ([^Y]+)? +#-----| 0 -> [RegExpGroup] ([^Y]+) + +# 436| [RegExpGroup] (x([^Y]+)?) +#-----| 0 -> [RegExpSequence] x([^Y]+)? + +# 436| [RegExpStar] (x([^Y]+)?)* +#-----| 0 -> [RegExpGroup] (x([^Y]+)?) + +# 436| [RegExpSequence] (x([^Y]+)?)*(Y|$) +#-----| 0 -> [RegExpStar] (x([^Y]+)?)* +#-----| 1 -> [RegExpGroup] (Y|$) + +# 436| [RegExpConstant, RegExpNormalChar] Y + +# 436| [RegExpConstant, RegExpNormalChar] Y + +# 436| [RegExpAlt] Y|$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] Y +#-----| 1 -> [RegExpDollar] $ + +# 436| [RegExpCharacterClass] [^Y] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] Y + +# 436| [RegExpPlus] [^Y]+ +#-----| 0 -> [RegExpCharacterClass] [^Y] + +# 436| [RegExpCaret] ^ + +# 436| [RegExpSequence] ^((x([^Y]+)?)*(Y|$)) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpGroup] ((x([^Y]+)?)*(Y|$)) + +# 436| [RegExpConstant, RegExpNormalChar] x + +# 436| [RegExpSequence] x([^Y]+)? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] x +#-----| 1 -> [RegExpOpt] ([^Y]+)? + +# 440| [RegExpGroup] ([\w-]*) +#-----| 0 -> [RegExpStar] [\w-]* + +# 440| [RegExpPlus] ([\w-]*)+ +#-----| 0 -> [RegExpGroup] ([\w-]*) + +# 440| [RegExpConstant, RegExpNormalChar] - + +# 440| [RegExpCharacterClass] [\w-] +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + +# 440| [RegExpStar] [\w-]* +#-----| 0 -> [RegExpCharacterClass] [\w-] + +# 440| [RegExpCharacterClassEscape] \w + +# 440| [RegExpConstant, RegExpNormalChar] bar + +# 440| [RegExpConstant, RegExpNormalChar] foo + +# 440| [RegExpSequence] foo([\w-]*)+bar +#-----| 0 -> [RegExpConstant, RegExpNormalChar] foo +#-----| 1 -> [RegExpPlus] ([\w-]*)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] bar + +# 444| [RegExpGroup] ((ab)*) +#-----| 0 -> [RegExpStar] (ab)* + +# 444| [RegExpPlus] ((ab)*)+ +#-----| 0 -> [RegExpGroup] ((ab)*) + +# 444| [RegExpSequence] ((ab)*)+c +#-----| 0 -> [RegExpPlus] ((ab)*)+ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] c + +# 444| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab + +# 444| [RegExpStar] (ab)* +#-----| 0 -> [RegExpGroup] (ab) + +# 444| [RegExpConstant, RegExpNormalChar] ab + +# 444| [RegExpConstant, RegExpNormalChar] c + +# 448| [RegExpGroup] (a?a?) +#-----| 0 -> [RegExpSequence] a?a? + +# 448| [RegExpStar] (a?a?)* +#-----| 0 -> [RegExpGroup] (a?a?) + +# 448| [RegExpSequence] (a?a?)*b +#-----| 0 -> [RegExpStar] (a?a?)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 448| [RegExpConstant, RegExpNormalChar] a + +# 448| [RegExpConstant, RegExpNormalChar] a + +# 448| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 448| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 448| [RegExpSequence] a?a? +#-----| 0 -> [RegExpOpt] a? +#-----| 1 -> [RegExpOpt] a? + +# 448| [RegExpConstant, RegExpNormalChar] b + +# 451| [RegExpGroup] (a?) +#-----| 0 -> [RegExpOpt] a? + +# 451| [RegExpStar] (a?)* +#-----| 0 -> [RegExpGroup] (a?) + +# 451| [RegExpSequence] (a?)*b +#-----| 0 -> [RegExpStar] (a?)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 451| [RegExpConstant, RegExpNormalChar] a + +# 451| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 451| [RegExpConstant, RegExpNormalChar] b + +# 455| [RegExpGroup] (c?a?) +#-----| 0 -> [RegExpSequence] c?a? + +# 455| [RegExpStar] (c?a?)* +#-----| 0 -> [RegExpGroup] (c?a?) + +# 455| [RegExpSequence] (c?a?)*b +#-----| 0 -> [RegExpStar] (c?a?)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 455| [RegExpConstant, RegExpNormalChar] a + +# 455| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 455| [RegExpConstant, RegExpNormalChar] b + +# 455| [RegExpConstant, RegExpNormalChar] c + +# 455| [RegExpOpt] c? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] c + +# 455| [RegExpSequence] c?a? +#-----| 0 -> [RegExpOpt] c? +#-----| 1 -> [RegExpOpt] a? + +# 459| [RegExpGroup] (?:a|a?) +#-----| 0 -> [RegExpAlt] a|a? + +# 459| [RegExpPlus] (?:a|a?)+ +#-----| 0 -> [RegExpGroup] (?:a|a?) + +# 459| [RegExpSequence] (?:a|a?)+b +#-----| 0 -> [RegExpPlus] (?:a|a?)+ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 459| [RegExpConstant, RegExpNormalChar] a + +# 459| [RegExpConstant, RegExpNormalChar] a + +# 459| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 459| [RegExpAlt] a|a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpOpt] a? + +# 459| [RegExpConstant, RegExpNormalChar] b + +# 463| [RegExpDollar] $ + +# 463| [RegExpGroup] (a?b?) +#-----| 0 -> [RegExpSequence] a?b? + +# 463| [RegExpStar] (a?b?)* +#-----| 0 -> [RegExpGroup] (a?b?) + +# 463| [RegExpSequence] (a?b?)*$ +#-----| 0 -> [RegExpStar] (a?b?)* +#-----| 1 -> [RegExpDollar] $ + +# 463| [RegExpConstant, RegExpNormalChar] a + +# 463| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 463| [RegExpSequence] a?b? +#-----| 0 -> [RegExpOpt] a? +#-----| 1 -> [RegExpOpt] b? + +# 463| [RegExpConstant, RegExpNormalChar] b + +# 463| [RegExpOpt] b? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b + +# 467| [RegExpDollar] $ + +# 467| [RegExpGroup] (([a-c]|[c-d])T(e?e?e?e?|X)) +#-----| 0 -> [RegExpSequence] ([a-c]|[c-d])T(e?e?e?e?|X) + +# 467| [RegExpPlus] (([a-c]|[c-d])T(e?e?e?e?|X))+ +#-----| 0 -> [RegExpGroup] (([a-c]|[c-d])T(e?e?e?e?|X)) + +# 467| [RegExpGroup] ([a-c]|[c-d]) +#-----| 0 -> [RegExpAlt] [a-c]|[c-d] + +# 467| [RegExpSequence] ([a-c]|[c-d])T(e?e?e?e?|X) +#-----| 0 -> [RegExpGroup] ([a-c]|[c-d]) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] T +#-----| 2 -> [RegExpGroup] (e?e?e?e?|X) + +# 467| [RegExpGroup] (cTcT|cTXcTX$) +#-----| 0 -> [RegExpAlt] cTcT|cTXcTX$ + +# 467| [RegExpGroup] (e?e?e?e?|X) +#-----| 0 -> [RegExpAlt] e?e?e?e?|X + +# 467| [RegExpConstant, RegExpNormalChar] PRE + +# 467| [RegExpSequence] PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] PRE +#-----| 1 -> [RegExpPlus] (([a-c]|[c-d])T(e?e?e?e?|X))+ +#-----| 2 -> [RegExpGroup] (cTcT|cTXcTX$) + +# 467| [RegExpConstant, RegExpNormalChar] T + +# 467| [RegExpConstant, RegExpNormalChar] X + +# 467| [RegExpCharacterClass] [a-c] +#-----| 0 -> [RegExpCharacterRange] a-c + +# 467| [RegExpAlt] [a-c]|[c-d] +#-----| 0 -> [RegExpCharacterClass] [a-c] +#-----| 1 -> [RegExpCharacterClass] [c-d] + +# 467| [RegExpCharacterClass] [c-d] +#-----| 0 -> [RegExpCharacterRange] c-d + +# 467| [RegExpConstant, RegExpNormalChar] a + +# 467| [RegExpCharacterRange] a-c +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] c + +# 467| [RegExpConstant, RegExpNormalChar] c + +# 467| [RegExpConstant, RegExpNormalChar] c + +# 467| [RegExpCharacterRange] c-d +#-----| 0 -> [RegExpConstant, RegExpNormalChar] c +#-----| 1 -> [RegExpConstant, RegExpNormalChar] d + +# 467| [RegExpConstant, RegExpNormalChar] cTXcTX + +# 467| [RegExpSequence] cTXcTX$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] cTXcTX +#-----| 1 -> [RegExpDollar] $ + +# 467| [RegExpConstant, RegExpNormalChar] cTcT + +# 467| [RegExpAlt] cTcT|cTXcTX$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] cTcT +#-----| 1 -> [RegExpSequence] cTXcTX$ + +# 467| [RegExpConstant, RegExpNormalChar] d + +# 467| [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpOpt] e? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpOpt] e? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpOpt] e? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpOpt] e? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpSequence] e?e?e?e? +#-----| 0 -> [RegExpOpt] e? +#-----| 1 -> [RegExpOpt] e? +#-----| 2 -> [RegExpOpt] e? +#-----| 3 -> [RegExpOpt] e? + +# 467| [RegExpAlt] e?e?e?e?|X +#-----| 0 -> [RegExpSequence] e?e?e?e? +#-----| 1 -> [RegExpConstant, RegExpNormalChar] X + +# 471| [RegExpDollar] $ + +# 471| [RegExpGroup] ((a)+\w) +#-----| 0 -> [RegExpSequence] (a)+\w + +# 471| [RegExpPlus] ((a)+\w)+ +#-----| 0 -> [RegExpGroup] ((a)+\w) + +# 471| [RegExpGroup] (a) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 471| [RegExpPlus] (a)+ +#-----| 0 -> [RegExpGroup] (a) + +# 471| [RegExpSequence] (a)+\w +#-----| 0 -> [RegExpPlus] (a)+ +#-----| 1 -> [RegExpCharacterClassEscape] \w + +# 471| [RegExpCharacterClassEscape] \w + +# 471| [RegExpCaret] ^ + +# 471| [RegExpSequence] ^((a)+\w)+$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ((a)+\w)+ +#-----| 2 -> [RegExpDollar] $ + +# 471| [RegExpConstant, RegExpNormalChar] a + +# 475| [RegExpDollar] $ + +# 475| [RegExpGroup] (b+.) +#-----| 0 -> [RegExpSequence] b+. + +# 475| [RegExpPlus] (b+.)+ +#-----| 0 -> [RegExpGroup] (b+.) + +# 475| [RegExpDot] . + +# 475| [RegExpCaret] ^ + +# 475| [RegExpSequence] ^(b+.)+$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] (b+.)+ +#-----| 2 -> [RegExpDollar] $ + +# 475| [RegExpConstant, RegExpNormalChar] b + +# 475| [RegExpPlus] b+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b + +# 475| [RegExpSequence] b+. +#-----| 0 -> [RegExpPlus] b+ +#-----| 1 -> [RegExpDot] . + +# 479| [RegExpGroup] (a*) +#-----| 0 -> [RegExpStar] a* + +# 479| [RegExpStar] (a*)* +#-----| 0 -> [RegExpGroup] (a*) + +# 479| [RegExpSequence] (a*)*b +#-----| 0 -> [RegExpStar] (a*)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 479| [RegExpConstant, RegExpNormalChar] a + +# 479| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 479| [RegExpConstant, RegExpNormalChar] b + +# 480| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 480| [RegExpStar] (a+)* +#-----| 0 -> [RegExpGroup] (a+) + +# 480| [RegExpSequence] (a+)*b +#-----| 0 -> [RegExpStar] (a+)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 480| [RegExpConstant, RegExpNormalChar] a + +# 480| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 480| [RegExpConstant, RegExpNormalChar] b + +# 481| [RegExpGroup] (a*) +#-----| 0 -> [RegExpStar] a* + +# 481| [RegExpPlus] (a*)+ +#-----| 0 -> [RegExpGroup] (a*) + +# 481| [RegExpSequence] (a*)+b +#-----| 0 -> [RegExpPlus] (a*)+ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 481| [RegExpConstant, RegExpNormalChar] a + +# 481| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 481| [RegExpConstant, RegExpNormalChar] b + +# 482| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 482| [RegExpPlus] (a+)+ +#-----| 0 -> [RegExpGroup] (a+) + +# 482| [RegExpSequence] (a+)+b +#-----| 0 -> [RegExpPlus] (a+)+ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 482| [RegExpConstant, RegExpNormalChar] a + +# 482| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 482| [RegExpConstant, RegExpNormalChar] b + +# 485| [RegExpGroup] (a|b) +#-----| 0 -> [RegExpAlt] a|b + +# 485| [RegExpPlus] (a|b)+ +#-----| 0 -> [RegExpGroup] (a|b) + +# 485| [RegExpConstant, RegExpNormalChar] a + +# 485| [RegExpAlt] a|b +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 485| [RegExpConstant, RegExpNormalChar] b + +# 488| [RegExpConstant, RegExpNormalChar] " + +# 488| [RegExpConstant, RegExpNormalChar] ' + +# 488| [RegExpConstant, RegExpNormalChar] ( + +# 488| [RegExpNegativeLookahead] (?![/\\]) + +# 488| [RegExpGroup] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\])) +#-----| 0 -> [RegExpAlt] [\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]) + +# 488| [RegExpPlus] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]))+ +#-----| 0 -> [RegExpGroup] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\])) + +# 488| [RegExpConstant, RegExpNormalChar] ) + +# 488| [RegExpConstant, RegExpNormalChar] * + +# 488| [RegExpConstant, RegExpNormalChar] + + +# 488| [RegExpConstant, RegExpNormalChar] , + +# 488| [RegExpConstant, RegExpNormalChar] / + +# 488| [RegExpConstant, RegExpNormalChar] : + +# 488| [RegExpSequence] :(?![/\\]) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] : +#-----| 1 -> [RegExpNegativeLookahead] (?![/\\]) + +# 488| [RegExpConstant, RegExpNormalChar] ; + +# 488| [RegExpConstant, RegExpNormalChar] < + +# 488| [RegExpConstant, RegExpNormalChar] = + +# 488| [RegExpConstant, RegExpNormalChar] > + +# 488| [RegExpConstant, RegExpNormalChar] @ + +# 488| [RegExpCharacterClass] [/\\] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] / +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 488| [RegExpCharacterClass] [\s;,"'<>(){}|\[\]@=+*] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpConstant, RegExpNormalChar] ; +#-----| 2 -> [RegExpConstant, RegExpNormalChar] , +#-----| 3 -> [RegExpConstant, RegExpNormalChar] " +#-----| 4 -> [RegExpConstant, RegExpNormalChar] ' +#-----| 5 -> [RegExpConstant, RegExpNormalChar] < +#-----| 6 -> [RegExpConstant, RegExpNormalChar] > +#-----| 7 -> [RegExpConstant, RegExpNormalChar] ( +#-----| 8 -> [RegExpConstant, RegExpNormalChar] ) +#-----| 9 -> [RegExpConstant, RegExpNormalChar] { +#-----| 10 -> [RegExpConstant, RegExpNormalChar] } +#-----| 11 -> [RegExpConstant, RegExpNormalChar] | +#-----| 12 -> [RegExpConstant, RegExpEscape] \[ +#-----| 13 -> [RegExpConstant, RegExpEscape] \] +#-----| 14 -> [RegExpConstant, RegExpNormalChar] @ +#-----| 15 -> [RegExpConstant, RegExpNormalChar] = +#-----| 16 -> [RegExpConstant, RegExpNormalChar] + +#-----| 17 -> [RegExpConstant, RegExpNormalChar] * + +# 488| [RegExpAlt] [\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]) +#-----| 0 -> [RegExpCharacterClass] [\s;,"'<>(){}|\[\]@=+*] +#-----| 1 -> [RegExpSequence] :(?![/\\]) + +# 488| [RegExpConstant, RegExpEscape] \[ + +# 488| [RegExpConstant, RegExpEscape] \\ + +# 488| [RegExpConstant, RegExpEscape] \] + +# 488| [RegExpCharacterClassEscape] \s + +# 488| [RegExpConstant, RegExpNormalChar] { + +# 488| [RegExpConstant, RegExpNormalChar] | + +# 488| [RegExpConstant, RegExpNormalChar] } + +# 492| [RegExpDollar] $ + +# 492| [RegExpGroup] ((?:a{|-)|\w\{) +#-----| 0 -> [RegExpAlt] (?:a{|-)|\w\{ + +# 492| [RegExpPlus] ((?:a{|-)|\w\{)+ +#-----| 0 -> [RegExpGroup] ((?:a{|-)|\w\{) + +# 492| [RegExpGroup] (?:a{|-) +#-----| 0 -> [RegExpAlt] a{|- + +# 492| [RegExpAlt] (?:a{|-)|\w\{ +#-----| 0 -> [RegExpGroup] (?:a{|-) +#-----| 1 -> [RegExpSequence] \w\{ + +# 492| [RegExpConstant, RegExpNormalChar] - + +# 492| [RegExpConstant, RegExpNormalChar] X + +# 492| [RegExpCharacterClassEscape] \w + +# 492| [RegExpSequence] \w\{ +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpEscape] \{ + +# 492| [RegExpConstant, RegExpEscape] \{ + +# 492| [RegExpCaret] ^ + +# 492| [RegExpSequence] ^((?:a{|-)|\w\{)+X$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ((?:a{|-)|\w\{)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] X +#-----| 3 -> [RegExpDollar] $ + +# 492| [RegExpConstant, RegExpNormalChar] a{ + +# 492| [RegExpAlt] a{|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + +# 493| [RegExpDollar] $ + +# 493| [RegExpGroup] ((?:a{0|-)|\w\{\d) +#-----| 0 -> [RegExpAlt] (?:a{0|-)|\w\{\d + +# 493| [RegExpPlus] ((?:a{0|-)|\w\{\d)+ +#-----| 0 -> [RegExpGroup] ((?:a{0|-)|\w\{\d) + +# 493| [RegExpGroup] (?:a{0|-) +#-----| 0 -> [RegExpAlt] a{0|- + +# 493| [RegExpAlt] (?:a{0|-)|\w\{\d +#-----| 0 -> [RegExpGroup] (?:a{0|-) +#-----| 1 -> [RegExpSequence] \w\{\d + +# 493| [RegExpConstant, RegExpNormalChar] - + +# 493| [RegExpConstant, RegExpNormalChar] X + +# 493| [RegExpCharacterClassEscape] \d + +# 493| [RegExpCharacterClassEscape] \w + +# 493| [RegExpSequence] \w\{\d +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpEscape] \{ +#-----| 2 -> [RegExpCharacterClassEscape] \d + +# 493| [RegExpConstant, RegExpEscape] \{ + +# 493| [RegExpCaret] ^ + +# 493| [RegExpSequence] ^((?:a{0|-)|\w\{\d)+X$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ((?:a{0|-)|\w\{\d)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] X +#-----| 3 -> [RegExpDollar] $ + +# 493| [RegExpConstant, RegExpNormalChar] a{0 + +# 493| [RegExpAlt] a{0|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + +# 494| [RegExpDollar] $ + +# 494| [RegExpGroup] ((?:a{0,|-)|\w\{\d,) +#-----| 0 -> [RegExpAlt] (?:a{0,|-)|\w\{\d, + +# 494| [RegExpPlus] ((?:a{0,|-)|\w\{\d,)+ +#-----| 0 -> [RegExpGroup] ((?:a{0,|-)|\w\{\d,) + +# 494| [RegExpGroup] (?:a{0,|-) +#-----| 0 -> [RegExpAlt] a{0,|- + +# 494| [RegExpAlt] (?:a{0,|-)|\w\{\d, +#-----| 0 -> [RegExpGroup] (?:a{0,|-) +#-----| 1 -> [RegExpSequence] \w\{\d, + +# 494| [RegExpConstant, RegExpNormalChar] , + +# 494| [RegExpConstant, RegExpNormalChar] - + +# 494| [RegExpConstant, RegExpNormalChar] X + +# 494| [RegExpCharacterClassEscape] \d + +# 494| [RegExpCharacterClassEscape] \w + +# 494| [RegExpSequence] \w\{\d, +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpEscape] \{ +#-----| 2 -> [RegExpCharacterClassEscape] \d +#-----| 3 -> [RegExpConstant, RegExpNormalChar] , + +# 494| [RegExpConstant, RegExpEscape] \{ + +# 494| [RegExpCaret] ^ + +# 494| [RegExpSequence] ^((?:a{0,|-)|\w\{\d,)+X$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ((?:a{0,|-)|\w\{\d,)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] X +#-----| 3 -> [RegExpDollar] $ + +# 494| [RegExpConstant, RegExpNormalChar] a{0, + +# 494| [RegExpAlt] a{0,|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0, +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + +# 495| [RegExpDollar] $ + +# 495| [RegExpGroup] ((?:a{0,2|-)|\w\{\d,\d) +#-----| 0 -> [RegExpAlt] (?:a{0,2|-)|\w\{\d,\d + +# 495| [RegExpPlus] ((?:a{0,2|-)|\w\{\d,\d)+ +#-----| 0 -> [RegExpGroup] ((?:a{0,2|-)|\w\{\d,\d) + +# 495| [RegExpGroup] (?:a{0,2|-) +#-----| 0 -> [RegExpAlt] a{0,2|- + +# 495| [RegExpAlt] (?:a{0,2|-)|\w\{\d,\d +#-----| 0 -> [RegExpGroup] (?:a{0,2|-) +#-----| 1 -> [RegExpSequence] \w\{\d,\d + +# 495| [RegExpConstant, RegExpNormalChar] , + +# 495| [RegExpConstant, RegExpNormalChar] - + +# 495| [RegExpConstant, RegExpNormalChar] X + +# 495| [RegExpCharacterClassEscape] \d + +# 495| [RegExpCharacterClassEscape] \d + +# 495| [RegExpCharacterClassEscape] \w + +# 495| [RegExpSequence] \w\{\d,\d +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpEscape] \{ +#-----| 2 -> [RegExpCharacterClassEscape] \d +#-----| 3 -> [RegExpConstant, RegExpNormalChar] , +#-----| 4 -> [RegExpCharacterClassEscape] \d + +# 495| [RegExpConstant, RegExpEscape] \{ + +# 495| [RegExpCaret] ^ + +# 495| [RegExpSequence] ^((?:a{0,2|-)|\w\{\d,\d)+X$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ((?:a{0,2|-)|\w\{\d,\d)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] X +#-----| 3 -> [RegExpDollar] $ + +# 495| [RegExpConstant, RegExpNormalChar] a{0,2 + +# 495| [RegExpAlt] a{0,2|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0,2 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + +# 498| [RegExpDollar] $ + +# 498| [RegExpGroup] ((?:a{0,2}|-)|\w\{\d,\d\}) +#-----| 0 -> [RegExpAlt] (?:a{0,2}|-)|\w\{\d,\d\} + +# 498| [RegExpPlus] ((?:a{0,2}|-)|\w\{\d,\d\})+ +#-----| 0 -> [RegExpGroup] ((?:a{0,2}|-)|\w\{\d,\d\}) + +# 498| [RegExpGroup] (?:a{0,2}|-) +#-----| 0 -> [RegExpAlt] a{0,2}|- + +# 498| [RegExpAlt] (?:a{0,2}|-)|\w\{\d,\d\} +#-----| 0 -> [RegExpGroup] (?:a{0,2}|-) +#-----| 1 -> [RegExpSequence] \w\{\d,\d\} + +# 498| [RegExpConstant, RegExpNormalChar] , + +# 498| [RegExpConstant, RegExpNormalChar] - + +# 498| [RegExpConstant, RegExpNormalChar] X + +# 498| [RegExpCharacterClassEscape] \d + +# 498| [RegExpCharacterClassEscape] \d + +# 498| [RegExpCharacterClassEscape] \w + +# 498| [RegExpSequence] \w\{\d,\d\} +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpEscape] \{ +#-----| 2 -> [RegExpCharacterClassEscape] \d +#-----| 3 -> [RegExpConstant, RegExpNormalChar] , +#-----| 4 -> [RegExpCharacterClassEscape] \d +#-----| 5 -> [RegExpConstant, RegExpEscape] \} + +# 498| [RegExpConstant, RegExpEscape] \{ + +# 498| [RegExpConstant, RegExpEscape] \} + +# 498| [RegExpCaret] ^ + +# 498| [RegExpSequence] ^((?:a{0,2}|-)|\w\{\d,\d\})+X$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ((?:a{0,2}|-)|\w\{\d,\d\})+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] X +#-----| 3 -> [RegExpDollar] $ + +# 498| [RegExpConstant, RegExpNormalChar] a + +# 498| [RegExpRange] a{0,2} +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 498| [RegExpAlt] a{0,2}|- +#-----| 0 -> [RegExpRange] a{0,2} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + +# 502| [RegExpGroup] (\u0061|a) +#-----| 0 -> [RegExpAlt] \u0061|a + +# 502| [RegExpStar] (\u0061|a)* +#-----| 0 -> [RegExpGroup] (\u0061|a) + +# 502| [RegExpConstant, RegExpNormalChar] X + +# 502| [RegExpSequence] X(\u0061|a)*Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpStar] (\u0061|a)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 502| [RegExpConstant, RegExpNormalChar] Y + +# 502| [RegExpConstant, RegExpEscape] \u0061 + +# 502| [RegExpAlt] \u0061|a +#-----| 0 -> [RegExpConstant, RegExpEscape] \u0061 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] a + +# 502| [RegExpConstant, RegExpNormalChar] a + +# 505| [RegExpGroup] (\u0061|b) +#-----| 0 -> [RegExpAlt] \u0061|b + +# 505| [RegExpPlus] (\u0061|b)+ +#-----| 0 -> [RegExpGroup] (\u0061|b) + +# 505| [RegExpConstant, RegExpNormalChar] X + +# 505| [RegExpSequence] X(\u0061|b)+Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpPlus] (\u0061|b)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 505| [RegExpConstant, RegExpNormalChar] Y + +# 505| [RegExpConstant, RegExpEscape] \u0061 + +# 505| [RegExpAlt] \u0061|b +#-----| 0 -> [RegExpConstant, RegExpEscape] \u0061 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 505| [RegExpConstant, RegExpNormalChar] b + +# 509| [RegExpGroup] (\U00000061|a) +#-----| 0 -> [RegExpAlt] \U00000061|a + +# 509| [RegExpStar] (\U00000061|a)* +#-----| 0 -> [RegExpGroup] (\U00000061|a) + +# 509| [RegExpConstant, RegExpNormalChar] X + +# 509| [RegExpSequence] X(\U00000061|a)*Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpStar] (\U00000061|a)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 509| [RegExpConstant, RegExpNormalChar] Y + +# 509| [RegExpConstant, RegExpEscape] \U00000061 + +# 509| [RegExpAlt] \U00000061|a +#-----| 0 -> [RegExpConstant, RegExpEscape] \U00000061 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] a + +# 509| [RegExpConstant, RegExpNormalChar] a + +# 512| [RegExpGroup] (\U00000061|b) +#-----| 0 -> [RegExpAlt] \U00000061|b + +# 512| [RegExpPlus] (\U00000061|b)+ +#-----| 0 -> [RegExpGroup] (\U00000061|b) + +# 512| [RegExpConstant, RegExpNormalChar] X + +# 512| [RegExpSequence] X(\U00000061|b)+Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpPlus] (\U00000061|b)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 512| [RegExpConstant, RegExpNormalChar] Y + +# 512| [RegExpConstant, RegExpEscape] \U00000061 + +# 512| [RegExpAlt] \U00000061|b +#-----| 0 -> [RegExpConstant, RegExpEscape] \U00000061 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 512| [RegExpConstant, RegExpNormalChar] b + +# 516| [RegExpGroup] (\x61|a) +#-----| 0 -> [RegExpAlt] \x61|a + +# 516| [RegExpStar] (\x61|a)* +#-----| 0 -> [RegExpGroup] (\x61|a) + +# 516| [RegExpConstant, RegExpNormalChar] X + +# 516| [RegExpSequence] X(\x61|a)*Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpStar] (\x61|a)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 516| [RegExpConstant, RegExpNormalChar] Y + +# 516| [RegExpConstant, RegExpEscape] \x61 + +# 516| [RegExpAlt] \x61|a +#-----| 0 -> [RegExpConstant, RegExpEscape] \x61 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] a + +# 516| [RegExpConstant, RegExpNormalChar] a + +# 519| [RegExpGroup] (\x61|b) +#-----| 0 -> [RegExpAlt] \x61|b + +# 519| [RegExpPlus] (\x61|b)+ +#-----| 0 -> [RegExpGroup] (\x61|b) + +# 519| [RegExpConstant, RegExpNormalChar] X + +# 519| [RegExpSequence] X(\x61|b)+Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpPlus] (\x61|b)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 519| [RegExpConstant, RegExpNormalChar] Y + +# 519| [RegExpConstant, RegExpEscape] \x61 + +# 519| [RegExpAlt] \x61|b +#-----| 0 -> [RegExpConstant, RegExpEscape] \x61 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 519| [RegExpConstant, RegExpNormalChar] b + +# 523| [RegExpGroup] (\x{061}|a) +#-----| 0 -> [RegExpAlt] \x{061}|a + +# 523| [RegExpStar] (\x{061}|a)* +#-----| 0 -> [RegExpGroup] (\x{061}|a) + +# 523| [RegExpConstant, RegExpNormalChar] X + +# 523| [RegExpSequence] X(\x{061}|a)*Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpStar] (\x{061}|a)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 523| [RegExpConstant, RegExpNormalChar] Y + +# 523| [RegExpConstant, RegExpEscape] \x{0 + +# 523| [RegExpConstant, RegExpEscape] \x{061} + +# 523| [RegExpAlt] \x{061}|a +#-----| 0 -> [RegExpConstant, RegExpEscape] \x{0 +#-----| 0 -> [RegExpConstant, RegExpEscape] \x{061} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] a + +# 523| [RegExpConstant, RegExpNormalChar] a + +# 526| [RegExpGroup] (\x{061}|b) +#-----| 0 -> [RegExpAlt] \x{061}|b + +# 526| [RegExpPlus] (\x{061}|b)+ +#-----| 0 -> [RegExpGroup] (\x{061}|b) + +# 526| [RegExpConstant, RegExpNormalChar] X + +# 526| [RegExpSequence] X(\x{061}|b)+Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpPlus] (\x{061}|b)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 526| [RegExpConstant, RegExpNormalChar] Y + +# 526| [RegExpConstant, RegExpEscape] \x{0 + +# 526| [RegExpConstant, RegExpEscape] \x{061} + +# 526| [RegExpAlt] \x{061}|b +#-----| 0 -> [RegExpConstant, RegExpEscape] \x{0 +#-----| 0 -> [RegExpConstant, RegExpEscape] \x{061} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 526| [RegExpConstant, RegExpNormalChar] b + +# 530| [RegExpGroup] (\p{Digit}|7) +#-----| 0 -> [RegExpAlt] \p{Digit}|7 + +# 530| [RegExpStar] (\p{Digit}|7)* +#-----| 0 -> [RegExpGroup] (\p{Digit}|7) + +# 530| [RegExpConstant, RegExpNormalChar] 7 + +# 530| [RegExpConstant, RegExpNormalChar] X + +# 530| [RegExpSequence] X(\p{Digit}|7)*Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpStar] (\p{Digit}|7)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 530| [RegExpConstant, RegExpNormalChar] Y + +# 530| [RegExpNamedCharacterProperty] \p{Digit} + +# 530| [RegExpAlt] \p{Digit}|7 +#-----| 0 -> [RegExpNamedCharacterProperty] \p{Digit} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 7 + +# 530| [RegExpAlt] |7 + +# 533| [RegExpGroup] (\p{Digit}|b) +#-----| 0 -> [RegExpAlt] \p{Digit}|b + +# 533| [RegExpPlus] (\p{Digit}|b)+ +#-----| 0 -> [RegExpGroup] (\p{Digit}|b) + +# 533| [RegExpConstant, RegExpNormalChar] X + +# 533| [RegExpSequence] X(\p{Digit}|b)+Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpPlus] (\p{Digit}|b)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 533| [RegExpConstant, RegExpNormalChar] Y + +# 533| [RegExpNamedCharacterProperty] \p{Digit} + +# 533| [RegExpAlt] \p{Digit}|b +#-----| 0 -> [RegExpNamedCharacterProperty] \p{Digit} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 533| [RegExpConstant, RegExpNormalChar] b + +# 533| [RegExpAlt] |b + +# 537| [RegExpGroup] (\P{Digit}|b) +#-----| 0 -> [RegExpAlt] \P{Digit}|b + +# 537| [RegExpStar] (\P{Digit}|b)* +#-----| 0 -> [RegExpGroup] (\P{Digit}|b) + +# 537| [RegExpConstant, RegExpNormalChar] X + +# 537| [RegExpSequence] X(\P{Digit}|b)*Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpStar] (\P{Digit}|b)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 537| [RegExpConstant, RegExpNormalChar] Y + +# 537| [RegExpNamedCharacterProperty] \P{Digit} + +# 537| [RegExpAlt] \P{Digit}|b +#-----| 0 -> [RegExpNamedCharacterProperty] \P{Digit} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 537| [RegExpConstant, RegExpNormalChar] b + +# 537| [RegExpAlt] |b + +# 540| [RegExpGroup] (\P{Digit}|7) +#-----| 0 -> [RegExpAlt] \P{Digit}|7 + +# 540| [RegExpPlus] (\P{Digit}|7)+ +#-----| 0 -> [RegExpGroup] (\P{Digit}|7) + +# 540| [RegExpConstant, RegExpNormalChar] 7 + +# 540| [RegExpConstant, RegExpNormalChar] X + +# 540| [RegExpSequence] X(\P{Digit}|7)+Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpPlus] (\P{Digit}|7)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 540| [RegExpConstant, RegExpNormalChar] Y + +# 540| [RegExpNamedCharacterProperty] \P{Digit} + +# 540| [RegExpAlt] \P{Digit}|7 +#-----| 0 -> [RegExpNamedCharacterProperty] \P{Digit} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 7 + +# 540| [RegExpAlt] |7 + +# 544| [RegExpGroup] (\p{IsDigit}|7) +#-----| 0 -> [RegExpAlt] \p{IsDigit}|7 + +# 544| [RegExpStar] (\p{IsDigit}|7)* +#-----| 0 -> [RegExpGroup] (\p{IsDigit}|7) + +# 544| [RegExpConstant, RegExpNormalChar] 7 + +# 544| [RegExpConstant, RegExpNormalChar] X + +# 544| [RegExpSequence] X(\p{IsDigit}|7)*Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpStar] (\p{IsDigit}|7)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 544| [RegExpConstant, RegExpNormalChar] Y + +# 544| [RegExpNamedCharacterProperty] \p{IsDigit} + +# 544| [RegExpAlt] \p{IsDigit}|7 +#-----| 0 -> [RegExpNamedCharacterProperty] \p{IsDigit} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 7 + +# 544| [RegExpAlt] |7 + +# 547| [RegExpGroup] (\p{IsDigit}|b) +#-----| 0 -> [RegExpAlt] \p{IsDigit}|b + +# 547| [RegExpPlus] (\p{IsDigit}|b)+ +#-----| 0 -> [RegExpGroup] (\p{IsDigit}|b) + +# 547| [RegExpConstant, RegExpNormalChar] X + +# 547| [RegExpSequence] X(\p{IsDigit}|b)+Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpPlus] (\p{IsDigit}|b)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 547| [RegExpConstant, RegExpNormalChar] Y + +# 547| [RegExpNamedCharacterProperty] \p{IsDigit} + +# 547| [RegExpAlt] \p{IsDigit}|b +#-----| 0 -> [RegExpNamedCharacterProperty] \p{IsDigit} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 547| [RegExpConstant, RegExpNormalChar] b + +# 547| [RegExpAlt] |b + +# 551| [RegExpGroup] (\p{Alpha}|a) +#-----| 0 -> [RegExpAlt] \p{Alpha}|a + +# 551| [RegExpStar] (\p{Alpha}|a)* +#-----| 0 -> [RegExpGroup] (\p{Alpha}|a) + +# 551| [RegExpConstant, RegExpNormalChar] X + +# 551| [RegExpSequence] X(\p{Alpha}|a)*Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpStar] (\p{Alpha}|a)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 551| [RegExpConstant, RegExpNormalChar] Y + +# 551| [RegExpNamedCharacterProperty] \p{Alpha} + +# 551| [RegExpAlt] \p{Alpha}|a +#-----| 0 -> [RegExpNamedCharacterProperty] \p{Alpha} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] a + +# 551| [RegExpConstant, RegExpNormalChar] a + +# 551| [RegExpAlt] |a + +# 554| [RegExpGroup] (\p{Alpha}|7) +#-----| 0 -> [RegExpAlt] \p{Alpha}|7 + +# 554| [RegExpPlus] (\p{Alpha}|7)+ +#-----| 0 -> [RegExpGroup] (\p{Alpha}|7) + +# 554| [RegExpConstant, RegExpNormalChar] 7 + +# 554| [RegExpConstant, RegExpNormalChar] X + +# 554| [RegExpSequence] X(\p{Alpha}|7)+Y +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X +#-----| 1 -> [RegExpPlus] (\p{Alpha}|7)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] Y + +# 554| [RegExpConstant, RegExpNormalChar] Y + +# 554| [RegExpNamedCharacterProperty] \p{Alpha} + +# 554| [RegExpAlt] \p{Alpha}|7 +#-----| 0 -> [RegExpNamedCharacterProperty] \p{Alpha} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 7 + +# 554| [RegExpAlt] |7 + +# 557| [RegExpConstant, RegExpNormalChar] " + +# 557| [RegExpConstant, RegExpNormalChar] " + +# 557| [RegExpConstant, RegExpNormalChar] " + +# 557| [RegExpConstant, RegExpNormalChar] " + +# 557| [RegExpSequence] "[^"]*?" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpStar] [^"]*? +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 557| [RegExpAlt] "[^"]*?"|[^"\s]+ +#-----| 0 -> [RegExpSequence] "[^"]*?" +#-----| 1 -> [RegExpPlus] [^"\s]+ + +# 557| [RegExpDollar] $ + +# 557| [RegExpGroup] ("[^"]*?"|[^"\s]+) +#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ + +# 557| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) + +# 557| [RegExpSequence] ("[^"]*?"|[^"\s]+)+(?=\s*|\s*$) +#-----| 0 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 1 -> [RegExpPositiveLookahead] (?=\s*|\s*$) + +# 557| [RegExpPositiveLookahead] (?=\s*|\s*$) + +# 557| [RegExpCharacterClass] [^"\s] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpCharacterClassEscape] \s + +# 557| [RegExpPlus] [^"\s]+ +#-----| 0 -> [RegExpCharacterClass] [^"\s] + +# 557| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " + +# 557| [RegExpStar] [^"]*? +#-----| 0 -> [RegExpCharacterClass] [^"] + +# 557| [RegExpCharacterClassEscape] \s + +# 557| [RegExpCharacterClassEscape] \s + +# 557| [RegExpCharacterClassEscape] \s + +# 557| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 557| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 557| [RegExpSequence] \s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpDollar] $ + +# 557| [RegExpAlt] \s*|\s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpSequence] \s*$ + +# 560| [RegExpConstant, RegExpNormalChar] " + +# 560| [RegExpConstant, RegExpNormalChar] " + +# 560| [RegExpConstant, RegExpNormalChar] " + +# 560| [RegExpConstant, RegExpNormalChar] " + +# 560| [RegExpSequence] "[^"]*?" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpStar] [^"]*? +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 560| [RegExpAlt] "[^"]*?"|[^"\s]+ +#-----| 0 -> [RegExpSequence] "[^"]*?" +#-----| 1 -> [RegExpPlus] [^"\s]+ + +# 560| [RegExpDollar] $ + +# 560| [RegExpGroup] ("[^"]*?"|[^"\s]+) +#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ + +# 560| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) + +# 560| [RegExpSequence] ("[^"]*?"|[^"\s]+)+(?=\s*|\s*$) +#-----| 0 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 1 -> [RegExpPositiveLookahead] (?=\s*|\s*$) + +# 560| [RegExpPositiveLookahead] (?=\s*|\s*$) + +# 560| [RegExpCharacterClass] [^"\s] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpCharacterClassEscape] \s + +# 560| [RegExpPlus] [^"\s]+ +#-----| 0 -> [RegExpCharacterClass] [^"\s] + +# 560| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " + +# 560| [RegExpStar] [^"]*? +#-----| 0 -> [RegExpCharacterClass] [^"] + +# 560| [RegExpCharacterClassEscape] \s + +# 560| [RegExpCharacterClassEscape] \s + +# 560| [RegExpCharacterClassEscape] \s + +# 560| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 560| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 560| [RegExpSequence] \s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpDollar] $ + +# 560| [RegExpAlt] \s*|\s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpSequence] \s*$ + +# 564| [RegExpConstant, RegExpNormalChar] " + +# 564| [RegExpConstant, RegExpNormalChar] " + +# 564| [RegExpConstant, RegExpNormalChar] " + +# 564| [RegExpConstant, RegExpNormalChar] " + +# 564| [RegExpSequence] "[^"]*?" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpStar] [^"]*? +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 564| [RegExpAlt] "[^"]*?"|[^"\s]+ +#-----| 0 -> [RegExpSequence] "[^"]*?" +#-----| 1 -> [RegExpPlus] [^"\s]+ + +# 564| [RegExpDollar] $ + +# 564| [RegExpGroup] ("[^"]*?"|[^"\s]+) +#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ + +# 564| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) + +# 564| [RegExpPositiveLookahead] (?=\s*|\s*$) + +# 564| [RegExpConstant, RegExpNormalChar] / + +# 564| [RegExpSequence] /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X +#-----| 0 -> [RegExpConstant, RegExpNormalChar] / +#-----| 1 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 2 -> [RegExpPositiveLookahead] (?=\s*|\s*$) +#-----| 3 -> [RegExpConstant, RegExpNormalChar] X + +# 564| [RegExpConstant, RegExpNormalChar] X + +# 564| [RegExpCharacterClass] [^"\s] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpCharacterClassEscape] \s + +# 564| [RegExpPlus] [^"\s]+ +#-----| 0 -> [RegExpCharacterClass] [^"\s] + +# 564| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " + +# 564| [RegExpStar] [^"]*? +#-----| 0 -> [RegExpCharacterClass] [^"] + +# 564| [RegExpCharacterClassEscape] \s + +# 564| [RegExpCharacterClassEscape] \s + +# 564| [RegExpCharacterClassEscape] \s + +# 564| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 564| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 564| [RegExpSequence] \s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpDollar] $ + +# 564| [RegExpAlt] \s*|\s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpSequence] \s*$ + +# 565| [RegExpConstant, RegExpNormalChar] " + +# 565| [RegExpConstant, RegExpNormalChar] " + +# 565| [RegExpConstant, RegExpNormalChar] " + +# 565| [RegExpConstant, RegExpNormalChar] " + +# 565| [RegExpSequence] "[^"]*?" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpStar] [^"]*? +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 565| [RegExpAlt] "[^"]*?"|[^"\s]+ +#-----| 0 -> [RegExpSequence] "[^"]*?" +#-----| 1 -> [RegExpPlus] [^"\s]+ + +# 565| [RegExpGroup] ("[^"]*?"|[^"\s]+) +#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ + +# 565| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) + +# 565| [RegExpPositiveLookahead] (?=X) + +# 565| [RegExpConstant, RegExpNormalChar] / + +# 565| [RegExpSequence] /("[^"]*?"|[^"\s]+)+(?=X) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] / +#-----| 1 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 2 -> [RegExpPositiveLookahead] (?=X) + +# 565| [RegExpConstant, RegExpNormalChar] X + +# 565| [RegExpCharacterClass] [^"\s] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpCharacterClassEscape] \s + +# 565| [RegExpPlus] [^"\s]+ +#-----| 0 -> [RegExpCharacterClass] [^"\s] + +# 565| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " + +# 565| [RegExpStar] [^"]*? +#-----| 0 -> [RegExpCharacterClass] [^"] + +# 565| [RegExpCharacterClassEscape] \s + +# 569| [RegExpGroup] (\d|0) +#-----| 0 -> [RegExpAlt] \d|0 + +# 569| [RegExpStar] (\d|0)* +#-----| 0 -> [RegExpGroup] (\d|0) + +# 569| [RegExpConstant, RegExpNormalChar] 0 + +# 569| [RegExpCaret] \A + +# 569| [RegExpSequence] \A(\d|0)*x +#-----| 0 -> [RegExpCaret] \A +#-----| 1 -> [RegExpStar] (\d|0)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] x + +# 569| [RegExpCharacterClassEscape] \d + +# 569| [RegExpAlt] \d|0 +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 0 + +# 569| [RegExpConstant, RegExpNormalChar] x + +# 570| [RegExpGroup] (\d|0) +#-----| 0 -> [RegExpAlt] \d|0 + +# 570| [RegExpStar] (\d|0)* +#-----| 0 -> [RegExpGroup] (\d|0) + +# 570| [RegExpSequence] (\d|0)*\Z +#-----| 0 -> [RegExpStar] (\d|0)* +#-----| 1 -> [RegExpDollar] \Z + +# 570| [RegExpConstant, RegExpNormalChar] 0 + +# 570| [RegExpDollar] \Z + +# 570| [RegExpCharacterClassEscape] \d + +# 570| [RegExpAlt] \d|0 +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 0 + +# 571| [RegExpGroup] (\d|0) +#-----| 0 -> [RegExpAlt] \d|0 + +# 571| [RegExpStar] (\d|0)* +#-----| 0 -> [RegExpGroup] (\d|0) + +# 571| [RegExpConstant, RegExpNormalChar] 0 + +# 571| [RegExpSpecialChar] \b + +# 571| [RegExpSequence] \b(\d|0)*x +#-----| 0 -> [RegExpSpecialChar] \b +#-----| 1 -> [RegExpStar] (\d|0)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] x + +# 571| [RegExpCharacterClassEscape] \d + +# 571| [RegExpAlt] \d|0 +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 0 + +# 571| [RegExpConstant, RegExpNormalChar] x + +# 574| [RegExpConstant, RegExpNormalChar] a + +# 574| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 574| [RegExpConstant, RegExpNormalChar] b + +# 575| [RegExpGroup] (a*) +#-----| 0 -> [RegExpStar] a* + +# 575| [RegExpStar] (a*)* +#-----| 0 -> [RegExpGroup] (a*) + +# 575| [RegExpConstant, RegExpNormalChar] a + +# 575| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 575| [RegExpConstant, RegExpNormalChar] b + +# 576| [RegExpConstant, RegExpNormalChar] a + +# 576| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 576| [RegExpConstant, RegExpNormalChar] b + +# 580| [RegExpConstant, RegExpNormalChar] a + +# 580| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 580| [RegExpConstant, RegExpNormalChar] aa + +# 580| [RegExpAlt] aa|a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] aa +#-----| 1 -> [RegExpStar] a* + +# 580| [RegExpConstant, RegExpNormalChar] b + +# 580| [RegExpConstant, RegExpNormalChar] c + +regex.swift: +# 103| [RegExpDot] . + +# 103| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 125| [RegExpDot] . + +# 125| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 142| [RegExpDot] . + +# 142| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 142| [RegExpDot] . + +# 142| [RegExpPlus] .+ +#-----| 0 -> [RegExpDot] . + +# 149| [RegExpGroup] ([\w.]+) +#-----| 0 -> [RegExpPlus] [\w.]+ + +# 149| [RegExpStar] ([\w.]+)* +#-----| 0 -> [RegExpGroup] ([\w.]+) + +# 149| [RegExpConstant, RegExpNormalChar] . + +# 149| [RegExpCharacterClass] [\w.] +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpNormalChar] . + +# 149| [RegExpPlus] [\w.]+ +#-----| 0 -> [RegExpCharacterClass] [\w.] + +# 149| [RegExpCharacterClassEscape] \w + +# 156| [RegExpConstant, RegExpNormalChar] +# 156| + +# 157| [RegExpConstant, RegExpEscape] \n + +# 158| [RegExpConstant, RegExpEscape] \n diff --git a/swift/ql/test/library-tests/regex/parse.ql b/swift/ql/test/library-tests/regex/parse.ql new file mode 100644 index 00000000000..52f9b67d9d2 --- /dev/null +++ b/swift/ql/test/library-tests/regex/parse.ql @@ -0,0 +1,27 @@ +/** + * @kind graph + */ + +import swift +import codeql.swift.regex.Regex as RE + +query predicate nodes(RE::RegExpTerm n, string attr, string val) { + attr = "semmle.label" and + val = "[" + concat(n.getAPrimaryQlClass(), ", ") + "] " + n.toString() + or + attr = "semmle.order" and + val = + any(int i | + n = + rank[i](RE::RegExpTerm t, string fp, int sl, int sc, int el, int ec | + t.hasLocationInfo(fp, sl, sc, el, ec) + | + t order by fp, sl, sc, el, ec, t.toString() + ) + ).toString() +} + +query predicate edges(RE::RegExpTerm pred, RE::RegExpTerm succ, string attr, string val) { + attr in ["semmle.label", "semmle.order"] and + val = any(int i | succ = pred.getChild(i)).toString() +} From e127030b5cf38806379ca25695c763bad6c8009b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 20 Jun 2023 16:23:21 +0100 Subject: [PATCH 255/364] Swift: Test some edge cases for locations. --- .../test/library-tests/regex/parse.expected | 19 +++++++++++++++++++ swift/ql/test/library-tests/regex/regex.swift | 19 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/swift/ql/test/library-tests/regex/parse.expected b/swift/ql/test/library-tests/regex/parse.expected index 15ccb286286..a738f329210 100644 --- a/swift/ql/test/library-tests/regex/parse.expected +++ b/swift/ql/test/library-tests/regex/parse.expected @@ -6254,3 +6254,22 @@ regex.swift: # 157| [RegExpConstant, RegExpEscape] \n # 158| [RegExpConstant, RegExpEscape] \n + +# 168| [RegExpConstant, RegExpNormalChar] aa + +# 168| [RegExpAlt] aa|bb +#-----| 0 -> [RegExpConstant, RegExpNormalChar] aa +#-----| 1 -> [RegExpConstant, RegExpNormalChar] bb + +# 168| [RegExpConstant, RegExpNormalChar] bb + +# 172| [RegExpConstant, RegExpNormalChar] +# 172| bb + +# 172| [RegExpConstant, RegExpNormalChar] aa + +# 172| [RegExpAlt] aa| +# 172| bb +#-----| 0 -> [RegExpConstant, RegExpNormalChar] aa +#-----| 1 -> [RegExpConstant, RegExpNormalChar] +#-----| bb diff --git a/swift/ql/test/library-tests/regex/regex.swift b/swift/ql/test/library-tests/regex/regex.swift index fbe52ba6fa4..ab372df9ffc 100644 --- a/swift/ql/test/library-tests/regex/regex.swift +++ b/swift/ql/test/library-tests/regex/regex.swift @@ -98,7 +98,7 @@ class NSRegularExpression : NSObject { // // the focus for these tests is different ways of evaluating regexps. -func myRegexpMethodsTests(b: Bool) throws { +func myRegexpMethodsTests(b: Bool, str_unknown: String) throws { let input = "abcdef" let regex = try Regex(".*") @@ -156,4 +156,21 @@ func myRegexpMethodsTests(b: Bool) throws { _ = try Regex("\n").firstMatch(in: input) // $ regex=NEWLINE input=input _ = try Regex("\\n").firstMatch(in: input) // $ regex=\n input=input _ = try Regex(#"\n"#).firstMatch(in: input) // $ regex=\n input=input + + // --- interpolated values --- + + let str_constant = "aa" + _ = try Regex("\(str_constant))|bb").firstMatch(in: input) // $ input=input MISSING: regex=aa|bb + _ = try Regex("\(str_unknown))|bb").firstMatch(in: input) // $ input=input + + // --- multi-line --- + + _ = try Regex(""" + aa|bb + """).firstMatch(in: input) // $ input=input regex=aa|bb + + _ = try Regex(""" + aa| + bb + """).firstMatch(in: input) // $ input=input regex=aa|NEWLINEbb } From 5a99007ab10630c36682c89540e4e5e5e44447b7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 20 Jun 2023 15:42:37 +0100 Subject: [PATCH 256/364] Swift: We don't need the location components logic inRegExpTerm, at least, not yet. --- .../lib/codeql/swift/regex/RegexTreeView.qll | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll index 3484462c989..c76153cc1e2 100644 --- a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll +++ b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll @@ -207,30 +207,10 @@ private module Impl implements RegexTreeViewSig { */ Location getLocation() { result = re.getLocation() } - /* - * pragma[noinline] - * private predicate componentHasLocationInfo( - * int i, string filepath, int startline, int startcolumn, int endline, int endcolumn - * ) { - * re.getComponent(i) - * .getLocation() - * .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - * } - */ - /** Holds if this term is found at the specified location offsets. */ predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - /* - * exists(int re_start | - * this.componentHasLocationInfo(0, filepath, startline, re_start, _, _) and - * this.componentHasLocationInfo(re.getNumberOfComponents() - 1, filepath, _, _, endline, _) and - * startcolumn = re_start + start and - * endcolumn = re_start + end - 1 - * ) - */ - filepath = re.getFile().getAbsolutePath() and startline = re.getLocation().getStartLine() and startcolumn = re.getLocation().getStartColumn() and From 5449bdc993a2c750c27a313825aa4d8d18b64fb7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 20 Jun 2023 17:13:14 +0100 Subject: [PATCH 257/364] Swift: Do regex locations more like Ruby does them. --- .../lib/codeql/swift/regex/RegexTreeView.qll | 4 +- .../test/library-tests/regex/parse.expected | 5008 ++++++++--------- 2 files changed, 2506 insertions(+), 2506 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll index c76153cc1e2..2cbd1bb0d52 100644 --- a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll +++ b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll @@ -213,9 +213,9 @@ private module Impl implements RegexTreeViewSig { ) { filepath = re.getFile().getAbsolutePath() and startline = re.getLocation().getStartLine() and - startcolumn = re.getLocation().getStartColumn() and + startcolumn = re.getLocation().getStartColumn() + start + 1 and endline = re.getLocation().getEndLine() and - endcolumn = re.getLocation().getEndColumn() + endcolumn = re.getLocation().getStartColumn() + end - 1 } /** Gets the file in which this term is found. */ diff --git a/swift/ql/test/library-tests/regex/parse.expected b/swift/ql/test/library-tests/regex/parse.expected index a738f329210..dc846fffdc8 100644 --- a/swift/ql/test/library-tests/regex/parse.expected +++ b/swift/ql/test/library-tests/regex/parse.expected @@ -89,20 +89,20 @@ redos_variants.swift: # 52| [RegExpConstant, RegExpNormalChar] a -# 52| [RegExpConstant, RegExpNormalChar] a - -# 52| [RegExpConstant, RegExpNormalChar] a - -# 52| [RegExpOpt] a? +# 52| [RegExpAlt] a|aa? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpSequence] aa? + +# 52| [RegExpConstant, RegExpNormalChar] a # 52| [RegExpSequence] aa? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpOpt] a? -# 52| [RegExpAlt] a|aa? +# 52| [RegExpConstant, RegExpNormalChar] a + +# 52| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpSequence] aa? # 52| [RegExpConstant, RegExpNormalChar] b @@ -118,33 +118,23 @@ redos_variants.swift: # 53| [RegExpConstant, RegExpNormalChar] a +# 53| [RegExpAlt] a|aa? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpSequence] aa? + # 53| [RegExpConstant, RegExpNormalChar] a +# 53| [RegExpSequence] aa? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpOpt] a? + # 53| [RegExpConstant, RegExpNormalChar] a # 53| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 53| [RegExpSequence] aa? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpOpt] a? - -# 53| [RegExpAlt] a|aa? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpSequence] aa? - # 53| [RegExpConstant, RegExpNormalChar] b -# 58| [RegExpDollar] $ - -# 58| [RegExpGroup] (__|.) -#-----| 0 -> [RegExpAlt] __|. - -# 58| [RegExpPlus] (__|.)+ -#-----| 0 -> [RegExpGroup] (__|.) - -# 58| [RegExpDot] . - # 58| [RegExpCaret] ^ # 58| [RegExpSequence] ^_(__|.)+_$ @@ -156,7 +146,11 @@ redos_variants.swift: # 58| [RegExpConstant, RegExpNormalChar] _ -# 58| [RegExpConstant, RegExpNormalChar] _ +# 58| [RegExpGroup] (__|.) +#-----| 0 -> [RegExpAlt] __|. + +# 58| [RegExpPlus] (__|.)+ +#-----| 0 -> [RegExpGroup] (__|.) # 58| [RegExpConstant, RegExpNormalChar] __ @@ -164,16 +158,11 @@ redos_variants.swift: #-----| 0 -> [RegExpConstant, RegExpNormalChar] __ #-----| 1 -> [RegExpDot] . -# 59| [RegExpDollar] $ +# 58| [RegExpDot] . -# 59| [RegExpGroup] (__|[^_]) -#-----| 0 -> [RegExpAlt] __|[^_] +# 58| [RegExpConstant, RegExpNormalChar] _ -# 59| [RegExpPlus] (__|[^_])+ -#-----| 0 -> [RegExpGroup] (__|[^_]) - -# 59| [RegExpCharacterClass] [^_] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] _ +# 58| [RegExpDollar] $ # 59| [RegExpCaret] ^ @@ -186,9 +175,11 @@ redos_variants.swift: # 59| [RegExpConstant, RegExpNormalChar] _ -# 59| [RegExpConstant, RegExpNormalChar] _ +# 59| [RegExpGroup] (__|[^_]) +#-----| 0 -> [RegExpAlt] __|[^_] -# 59| [RegExpConstant, RegExpNormalChar] _ +# 59| [RegExpPlus] (__|[^_])+ +#-----| 0 -> [RegExpGroup] (__|[^_]) # 59| [RegExpConstant, RegExpNormalChar] __ @@ -196,75 +187,17 @@ redos_variants.swift: #-----| 0 -> [RegExpConstant, RegExpNormalChar] __ #-----| 1 -> [RegExpCharacterClass] [^_] -# 66| [RegExpGroup] ((?:\*\*|[\s\S])+?) -#-----| 0 -> [RegExpPlus] (?:\*\*|[\s\S])+? +# 59| [RegExpCharacterClass] [^_] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] _ -# 66| [RegExpGroup] ((?:__|[\s\S])+?) -#-----| 0 -> [RegExpPlus] (?:__|[\s\S])+? +# 59| [RegExpConstant, RegExpNormalChar] _ -# 66| [RegExpNegativeLookahead] (?!\*) +# 59| [RegExpConstant, RegExpNormalChar] _ -# 66| [RegExpGroup] (?:\*\*|[\s\S]) -#-----| 0 -> [RegExpAlt] \*\*|[\s\S] - -# 66| [RegExpPlus] (?:\*\*|[\s\S])+? -#-----| 0 -> [RegExpGroup] (?:\*\*|[\s\S]) - -# 66| [RegExpGroup] (?:__|[\s\S]) -#-----| 0 -> [RegExpAlt] __|[\s\S] - -# 66| [RegExpPlus] (?:__|[\s\S])+? -#-----| 0 -> [RegExpGroup] (?:__|[\s\S]) - -# 66| [RegExpCharacterClass] [\s\S] -#-----| 0 -> [RegExpCharacterClassEscape] \s -#-----| 1 -> [RegExpCharacterClassEscape] \S - -# 66| [RegExpCharacterClass] [\s\S] -#-----| 0 -> [RegExpCharacterClassEscape] \s -#-----| 1 -> [RegExpCharacterClassEscape] \S - -# 66| [RegExpConstant, RegExpEscape] \* - -# 66| [RegExpConstant, RegExpEscape] \* - -# 66| [RegExpConstant, RegExpEscape] \* - -# 66| [RegExpConstant, RegExpEscape] \* - -# 66| [RegExpConstant, RegExpEscape] \* - -# 66| [RegExpSequence] \*\* -#-----| 0 -> [RegExpConstant, RegExpEscape] \* -#-----| 1 -> [RegExpConstant, RegExpEscape] \* - -# 66| [RegExpAlt] \*\*|[\s\S] -#-----| 0 -> [RegExpSequence] \*\* -#-----| 1 -> [RegExpCharacterClass] [\s\S] - -# 66| [RegExpCharacterClassEscape] \S - -# 66| [RegExpCharacterClassEscape] \S - -# 66| [RegExpSpecialChar] \b - -# 66| [RegExpSpecialChar] \b - -# 66| [RegExpCharacterClassEscape] \s - -# 66| [RegExpCharacterClassEscape] \s +# 59| [RegExpDollar] $ # 66| [RegExpCaret] ^ -# 66| [RegExpCaret] ^ - -# 66| [RegExpSequence] ^\*((?:\*\*|[\s\S])+?)\*(?!\*) -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpConstant, RegExpEscape] \* -#-----| 2 -> [RegExpGroup] ((?:\*\*|[\s\S])+?) -#-----| 3 -> [RegExpConstant, RegExpEscape] \* -#-----| 4 -> [RegExpNegativeLookahead] (?!\*) - # 66| [RegExpSequence] ^\b_((?:__|[\s\S])+?)_\b #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpSpecialChar] \b @@ -277,85 +210,85 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] ^\b_((?:__|[\s\S])+?)_\b #-----| 1 -> [RegExpSequence] ^\*((?:\*\*|[\s\S])+?)\*(?!\*) -# 66| [RegExpConstant, RegExpNormalChar] _ +# 66| [RegExpSpecialChar] \b # 66| [RegExpConstant, RegExpNormalChar] _ +# 66| [RegExpGroup] ((?:__|[\s\S])+?) +#-----| 0 -> [RegExpPlus] (?:__|[\s\S])+? + +# 66| [RegExpGroup] (?:__|[\s\S]) +#-----| 0 -> [RegExpAlt] __|[\s\S] + +# 66| [RegExpPlus] (?:__|[\s\S])+? +#-----| 0 -> [RegExpGroup] (?:__|[\s\S]) + # 66| [RegExpConstant, RegExpNormalChar] __ # 66| [RegExpAlt] __|[\s\S] #-----| 0 -> [RegExpConstant, RegExpNormalChar] __ #-----| 1 -> [RegExpCharacterClass] [\s\S] -# 69| [RegExpGroup] ((?:\*\*|[\s\S])+?) -#-----| 0 -> [RegExpPlus] (?:\*\*|[\s\S])+? - -# 69| [RegExpGroup] ((?:__|[\s\S])+?) -#-----| 0 -> [RegExpPlus] (?:__|[\s\S])+? - -# 69| [RegExpNegativeLookahead] (?!\*) - -# 69| [RegExpGroup] (?:\*\*|[\s\S]) -#-----| 0 -> [RegExpAlt] \*\*|[\s\S] - -# 69| [RegExpPlus] (?:\*\*|[\s\S])+? -#-----| 0 -> [RegExpGroup] (?:\*\*|[\s\S]) - -# 69| [RegExpGroup] (?:__|[\s\S]) -#-----| 0 -> [RegExpAlt] __|[\s\S] - -# 69| [RegExpPlus] (?:__|[\s\S])+? -#-----| 0 -> [RegExpGroup] (?:__|[\s\S]) - -# 69| [RegExpCharacterClass] [\s\S] +# 66| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S -# 69| [RegExpCharacterClass] [\s\S] -#-----| 0 -> [RegExpCharacterClassEscape] \s -#-----| 1 -> [RegExpCharacterClassEscape] \S +# 66| [RegExpCharacterClassEscape] \s -# 69| [RegExpConstant, RegExpEscape] \* +# 66| [RegExpCharacterClassEscape] \S -# 69| [RegExpConstant, RegExpEscape] \* +# 66| [RegExpConstant, RegExpNormalChar] _ -# 69| [RegExpConstant, RegExpEscape] \* +# 66| [RegExpSpecialChar] \b -# 69| [RegExpConstant, RegExpEscape] \* +# 66| [RegExpCaret] ^ -# 69| [RegExpConstant, RegExpEscape] \* - -# 69| [RegExpSequence] \*\* -#-----| 0 -> [RegExpConstant, RegExpEscape] \* -#-----| 1 -> [RegExpConstant, RegExpEscape] \* - -# 69| [RegExpAlt] \*\*|[\s\S] -#-----| 0 -> [RegExpSequence] \*\* -#-----| 1 -> [RegExpCharacterClass] [\s\S] - -# 69| [RegExpCharacterClassEscape] \S - -# 69| [RegExpCharacterClassEscape] \S - -# 69| [RegExpSpecialChar] \b - -# 69| [RegExpSpecialChar] \b - -# 69| [RegExpCharacterClassEscape] \s - -# 69| [RegExpCharacterClassEscape] \s - -# 69| [RegExpCaret] ^ - -# 69| [RegExpCaret] ^ - -# 69| [RegExpSequence] ^\*((?:\*\*|[\s\S])+?)\*(?!\*) +# 66| [RegExpSequence] ^\*((?:\*\*|[\s\S])+?)\*(?!\*) #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpConstant, RegExpEscape] \* #-----| 2 -> [RegExpGroup] ((?:\*\*|[\s\S])+?) #-----| 3 -> [RegExpConstant, RegExpEscape] \* #-----| 4 -> [RegExpNegativeLookahead] (?!\*) +# 66| [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpGroup] ((?:\*\*|[\s\S])+?) +#-----| 0 -> [RegExpPlus] (?:\*\*|[\s\S])+? + +# 66| [RegExpGroup] (?:\*\*|[\s\S]) +#-----| 0 -> [RegExpAlt] \*\*|[\s\S] + +# 66| [RegExpPlus] (?:\*\*|[\s\S])+? +#-----| 0 -> [RegExpGroup] (?:\*\*|[\s\S]) + +# 66| [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpSequence] \*\* +#-----| 0 -> [RegExpConstant, RegExpEscape] \* +#-----| 1 -> [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpAlt] \*\*|[\s\S] +#-----| 0 -> [RegExpSequence] \*\* +#-----| 1 -> [RegExpCharacterClass] [\s\S] + +# 66| [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 66| [RegExpCharacterClassEscape] \s + +# 66| [RegExpCharacterClassEscape] \S + +# 66| [RegExpConstant, RegExpEscape] \* + +# 66| [RegExpNegativeLookahead] (?!\*) + +# 66| [RegExpConstant, RegExpEscape] \* + +# 69| [RegExpCaret] ^ + # 69| [RegExpSequence] ^\b_((?:__|[\s\S])+?)_\b #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpSpecialChar] \b @@ -368,77 +301,85 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] ^\b_((?:__|[\s\S])+?)_\b #-----| 1 -> [RegExpSequence] ^\*((?:\*\*|[\s\S])+?)\*(?!\*) -# 69| [RegExpConstant, RegExpNormalChar] _ +# 69| [RegExpSpecialChar] \b # 69| [RegExpConstant, RegExpNormalChar] _ +# 69| [RegExpGroup] ((?:__|[\s\S])+?) +#-----| 0 -> [RegExpPlus] (?:__|[\s\S])+? + +# 69| [RegExpGroup] (?:__|[\s\S]) +#-----| 0 -> [RegExpAlt] __|[\s\S] + +# 69| [RegExpPlus] (?:__|[\s\S])+? +#-----| 0 -> [RegExpGroup] (?:__|[\s\S]) + # 69| [RegExpConstant, RegExpNormalChar] __ # 69| [RegExpAlt] __|[\s\S] #-----| 0 -> [RegExpConstant, RegExpNormalChar] __ #-----| 1 -> [RegExpCharacterClass] [\s\S] -# 74| [RegExpGroup] ((?:\*\*|[^*])+?) -#-----| 0 -> [RegExpPlus] (?:\*\*|[^*])+? +# 69| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S -# 74| [RegExpGroup] ((?:__|[^_])+?) -#-----| 0 -> [RegExpPlus] (?:__|[^_])+? +# 69| [RegExpCharacterClassEscape] \s -# 74| [RegExpNegativeLookahead] (?!\*) +# 69| [RegExpCharacterClassEscape] \S -# 74| [RegExpGroup] (?:\*\*|[^*]) -#-----| 0 -> [RegExpAlt] \*\*|[^*] +# 69| [RegExpConstant, RegExpNormalChar] _ -# 74| [RegExpPlus] (?:\*\*|[^*])+? -#-----| 0 -> [RegExpGroup] (?:\*\*|[^*]) +# 69| [RegExpSpecialChar] \b -# 74| [RegExpGroup] (?:__|[^_]) -#-----| 0 -> [RegExpAlt] __|[^_] +# 69| [RegExpCaret] ^ -# 74| [RegExpPlus] (?:__|[^_])+? -#-----| 0 -> [RegExpGroup] (?:__|[^_]) +# 69| [RegExpSequence] ^\*((?:\*\*|[\s\S])+?)\*(?!\*) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpConstant, RegExpEscape] \* +#-----| 2 -> [RegExpGroup] ((?:\*\*|[\s\S])+?) +#-----| 3 -> [RegExpConstant, RegExpEscape] \* +#-----| 4 -> [RegExpNegativeLookahead] (?!\*) -# 74| [RegExpConstant, RegExpNormalChar] * +# 69| [RegExpConstant, RegExpEscape] \* -# 74| [RegExpCharacterClass] [^*] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] * +# 69| [RegExpGroup] ((?:\*\*|[\s\S])+?) +#-----| 0 -> [RegExpPlus] (?:\*\*|[\s\S])+? -# 74| [RegExpCharacterClass] [^_] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] _ +# 69| [RegExpGroup] (?:\*\*|[\s\S]) +#-----| 0 -> [RegExpAlt] \*\*|[\s\S] -# 74| [RegExpConstant, RegExpEscape] \* +# 69| [RegExpPlus] (?:\*\*|[\s\S])+? +#-----| 0 -> [RegExpGroup] (?:\*\*|[\s\S]) -# 74| [RegExpConstant, RegExpEscape] \* +# 69| [RegExpConstant, RegExpEscape] \* -# 74| [RegExpConstant, RegExpEscape] \* - -# 74| [RegExpConstant, RegExpEscape] \* - -# 74| [RegExpConstant, RegExpEscape] \* - -# 74| [RegExpSequence] \*\* +# 69| [RegExpSequence] \*\* #-----| 0 -> [RegExpConstant, RegExpEscape] \* #-----| 1 -> [RegExpConstant, RegExpEscape] \* -# 74| [RegExpAlt] \*\*|[^*] +# 69| [RegExpAlt] \*\*|[\s\S] #-----| 0 -> [RegExpSequence] \*\* -#-----| 1 -> [RegExpCharacterClass] [^*] +#-----| 1 -> [RegExpCharacterClass] [\s\S] -# 74| [RegExpSpecialChar] \b +# 69| [RegExpConstant, RegExpEscape] \* -# 74| [RegExpSpecialChar] \b +# 69| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 69| [RegExpCharacterClassEscape] \s + +# 69| [RegExpCharacterClassEscape] \S + +# 69| [RegExpConstant, RegExpEscape] \* + +# 69| [RegExpNegativeLookahead] (?!\*) + +# 69| [RegExpConstant, RegExpEscape] \* # 74| [RegExpCaret] ^ -# 74| [RegExpCaret] ^ - -# 74| [RegExpSequence] ^\*((?:\*\*|[^*])+?)\*(?!\*) -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpConstant, RegExpEscape] \* -#-----| 2 -> [RegExpGroup] ((?:\*\*|[^*])+?) -#-----| 3 -> [RegExpConstant, RegExpEscape] \* -#-----| 4 -> [RegExpNegativeLookahead] (?!\*) - # 74| [RegExpSequence] ^\b_((?:__|[^_])+?)_\b #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpSpecialChar] \b @@ -451,11 +392,18 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] ^\b_((?:__|[^_])+?)_\b #-----| 1 -> [RegExpSequence] ^\*((?:\*\*|[^*])+?)\*(?!\*) -# 74| [RegExpConstant, RegExpNormalChar] _ +# 74| [RegExpSpecialChar] \b # 74| [RegExpConstant, RegExpNormalChar] _ -# 74| [RegExpConstant, RegExpNormalChar] _ +# 74| [RegExpGroup] ((?:__|[^_])+?) +#-----| 0 -> [RegExpPlus] (?:__|[^_])+? + +# 74| [RegExpGroup] (?:__|[^_]) +#-----| 0 -> [RegExpAlt] __|[^_] + +# 74| [RegExpPlus] (?:__|[^_])+? +#-----| 0 -> [RegExpGroup] (?:__|[^_]) # 74| [RegExpConstant, RegExpNormalChar] __ @@ -463,6 +411,58 @@ redos_variants.swift: #-----| 0 -> [RegExpConstant, RegExpNormalChar] __ #-----| 1 -> [RegExpCharacterClass] [^_] +# 74| [RegExpCharacterClass] [^_] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] _ + +# 74| [RegExpConstant, RegExpNormalChar] _ + +# 74| [RegExpConstant, RegExpNormalChar] _ + +# 74| [RegExpSpecialChar] \b + +# 74| [RegExpCaret] ^ + +# 74| [RegExpSequence] ^\*((?:\*\*|[^*])+?)\*(?!\*) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpConstant, RegExpEscape] \* +#-----| 2 -> [RegExpGroup] ((?:\*\*|[^*])+?) +#-----| 3 -> [RegExpConstant, RegExpEscape] \* +#-----| 4 -> [RegExpNegativeLookahead] (?!\*) + +# 74| [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpGroup] ((?:\*\*|[^*])+?) +#-----| 0 -> [RegExpPlus] (?:\*\*|[^*])+? + +# 74| [RegExpGroup] (?:\*\*|[^*]) +#-----| 0 -> [RegExpAlt] \*\*|[^*] + +# 74| [RegExpPlus] (?:\*\*|[^*])+? +#-----| 0 -> [RegExpGroup] (?:\*\*|[^*]) + +# 74| [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpSequence] \*\* +#-----| 0 -> [RegExpConstant, RegExpEscape] \* +#-----| 1 -> [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpAlt] \*\*|[^*] +#-----| 0 -> [RegExpSequence] \*\* +#-----| 1 -> [RegExpCharacterClass] [^*] + +# 74| [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpCharacterClass] [^*] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] * + +# 74| [RegExpConstant, RegExpNormalChar] * + +# 74| [RegExpConstant, RegExpEscape] \* + +# 74| [RegExpNegativeLookahead] (?!\*) + +# 74| [RegExpConstant, RegExpEscape] \* + # 79| [RegExpGroup] (.*,) #-----| 0 -> [RegExpSequence] .*, @@ -473,10 +473,6 @@ redos_variants.swift: #-----| 0 -> [RegExpPlus] (.*,)+ #-----| 1 -> [RegExpPlus] .+ -# 79| [RegExpConstant, RegExpNormalChar] , - -# 79| [RegExpDot] . - # 79| [RegExpDot] . # 79| [RegExpStar] .* @@ -486,12 +482,36 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] .* #-----| 1 -> [RegExpConstant, RegExpNormalChar] , +# 79| [RegExpConstant, RegExpNormalChar] , + +# 79| [RegExpDot] . + # 79| [RegExpPlus] .+ #-----| 0 -> [RegExpDot] . -# 85| [RegExpConstant, RegExpNormalChar] " +# 85| [RegExpCaret] ^ -# 85| [RegExpConstant, RegExpNormalChar] " +# 85| [RegExpSequence] ^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))? +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpOpt] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))? + +# 85| [RegExpGroup] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\))) +#-----| 0 -> [RegExpSequence] \s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) + +# 85| [RegExpOpt] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))? +#-----| 0 -> [RegExpGroup] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\))) + +# 85| [RegExpCharacterClassEscape] \s + +# 85| [RegExpPlus] \s+ +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 85| [RegExpSequence] \s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) +#-----| 0 -> [RegExpPlus] \s+ +#-----| 1 -> [RegExpGroup] (?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) + +# 85| [RegExpGroup] (?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) +#-----| 0 -> [RegExpAlt] "(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\) # 85| [RegExpConstant, RegExpNormalChar] " @@ -505,52 +525,12 @@ redos_variants.swift: #-----| 1 -> [RegExpSequence] '(?:[^'\\]|\\\\|\\.)+' #-----| 2 -> [RegExpSequence] \((?:[^)\\]|\\\\|\\.)+\) -# 85| [RegExpConstant, RegExpNormalChar] ' - -# 85| [RegExpConstant, RegExpNormalChar] ' - -# 85| [RegExpConstant, RegExpNormalChar] ' - -# 85| [RegExpSequence] '(?:[^'\\]|\\\\|\\.)+' -#-----| 0 -> [RegExpConstant, RegExpNormalChar] ' -#-----| 1 -> [RegExpPlus] (?:[^'\\]|\\\\|\\.)+ -#-----| 2 -> [RegExpConstant, RegExpNormalChar] ' - -# 85| [RegExpGroup] (?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) -#-----| 0 -> [RegExpAlt] "(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\) - # 85| [RegExpGroup] (?:[^"\\]|\\\\|\\.) #-----| 0 -> [RegExpAlt] [^"\\]|\\\\|\\. # 85| [RegExpPlus] (?:[^"\\]|\\\\|\\.)+ #-----| 0 -> [RegExpGroup] (?:[^"\\]|\\\\|\\.) -# 85| [RegExpGroup] (?:[^'\\]|\\\\|\\.) -#-----| 0 -> [RegExpAlt] [^'\\]|\\\\|\\. - -# 85| [RegExpPlus] (?:[^'\\]|\\\\|\\.)+ -#-----| 0 -> [RegExpGroup] (?:[^'\\]|\\\\|\\.) - -# 85| [RegExpGroup] (?:[^)\\]|\\\\|\\.) -#-----| 0 -> [RegExpAlt] [^)\\]|\\\\|\\. - -# 85| [RegExpPlus] (?:[^)\\]|\\\\|\\.)+ -#-----| 0 -> [RegExpGroup] (?:[^)\\]|\\\\|\\.) - -# 85| [RegExpGroup] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\))) -#-----| 0 -> [RegExpSequence] \s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) - -# 85| [RegExpOpt] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))? -#-----| 0 -> [RegExpGroup] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\))) - -# 85| [RegExpConstant, RegExpNormalChar] ) - -# 85| [RegExpDot] . - -# 85| [RegExpDot] . - -# 85| [RegExpDot] . - # 85| [RegExpCharacterClass] [^"\\] #-----| 0 -> [RegExpConstant, RegExpNormalChar] " #-----| 1 -> [RegExpConstant, RegExpEscape] \\ @@ -560,6 +540,41 @@ redos_variants.swift: #-----| 1 -> [RegExpSequence] \\\\ #-----| 2 -> [RegExpSequence] \\. +# 85| [RegExpConstant, RegExpNormalChar] " + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpSequence] \\\\ +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpSequence] \\. +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpDot] . + +# 85| [RegExpDot] . + +# 85| [RegExpConstant, RegExpNormalChar] " + +# 85| [RegExpConstant, RegExpNormalChar] ' + +# 85| [RegExpSequence] '(?:[^'\\]|\\\\|\\.)+' +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ' +#-----| 1 -> [RegExpPlus] (?:[^'\\]|\\\\|\\.)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] ' + +# 85| [RegExpGroup] (?:[^'\\]|\\\\|\\.) +#-----| 0 -> [RegExpAlt] [^'\\]|\\\\|\\. + +# 85| [RegExpPlus] (?:[^'\\]|\\\\|\\.)+ +#-----| 0 -> [RegExpGroup] (?:[^'\\]|\\\\|\\.) + # 85| [RegExpCharacterClass] [^'\\] #-----| 0 -> [RegExpConstant, RegExpNormalChar] ' #-----| 1 -> [RegExpConstant, RegExpEscape] \\ @@ -569,6 +584,41 @@ redos_variants.swift: #-----| 1 -> [RegExpSequence] \\\\ #-----| 2 -> [RegExpSequence] \\. +# 85| [RegExpConstant, RegExpNormalChar] ' + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpSequence] \\\\ +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpSequence] \\. +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpDot] . + +# 85| [RegExpDot] . + +# 85| [RegExpConstant, RegExpNormalChar] ' + +# 85| [RegExpConstant, RegExpEscape] \( + +# 85| [RegExpSequence] \((?:[^)\\]|\\\\|\\.)+\) +#-----| 0 -> [RegExpConstant, RegExpEscape] \( +#-----| 1 -> [RegExpPlus] (?:[^)\\]|\\\\|\\.)+ +#-----| 2 -> [RegExpConstant, RegExpEscape] \) + +# 85| [RegExpGroup] (?:[^)\\]|\\\\|\\.) +#-----| 0 -> [RegExpAlt] [^)\\]|\\\\|\\. + +# 85| [RegExpPlus] (?:[^)\\]|\\\\|\\.)+ +#-----| 0 -> [RegExpGroup] (?:[^)\\]|\\\\|\\.) + # 85| [RegExpCharacterClass] [^)\\] #-----| 0 -> [RegExpConstant, RegExpNormalChar] ) #-----| 1 -> [RegExpConstant, RegExpEscape] \\ @@ -578,200 +628,28 @@ redos_variants.swift: #-----| 1 -> [RegExpSequence] \\\\ #-----| 2 -> [RegExpSequence] \\. -# 85| [RegExpConstant, RegExpEscape] \( +# 85| [RegExpConstant, RegExpNormalChar] ) -# 85| [RegExpSequence] \((?:[^)\\]|\\\\|\\.)+\) -#-----| 0 -> [RegExpConstant, RegExpEscape] \( -#-----| 1 -> [RegExpPlus] (?:[^)\\]|\\\\|\\.)+ -#-----| 2 -> [RegExpConstant, RegExpEscape] \) +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpSequence] \\\\ +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpConstant, RegExpEscape] \\ + +# 85| [RegExpSequence] \\. +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpDot] . + +# 85| [RegExpDot] . # 85| [RegExpConstant, RegExpEscape] \) -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpSequence] \\. -#-----| 0 -> [RegExpConstant, RegExpEscape] \\ -#-----| 1 -> [RegExpDot] . - -# 85| [RegExpSequence] \\. -#-----| 0 -> [RegExpConstant, RegExpEscape] \\ -#-----| 1 -> [RegExpDot] . - -# 85| [RegExpSequence] \\. -#-----| 0 -> [RegExpConstant, RegExpEscape] \\ -#-----| 1 -> [RegExpDot] . - -# 85| [RegExpSequence] \\\\ -#-----| 0 -> [RegExpConstant, RegExpEscape] \\ -#-----| 1 -> [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpSequence] \\\\ -#-----| 0 -> [RegExpConstant, RegExpEscape] \\ -#-----| 1 -> [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpSequence] \\\\ -#-----| 0 -> [RegExpConstant, RegExpEscape] \\ -#-----| 1 -> [RegExpConstant, RegExpEscape] \\ - -# 85| [RegExpCharacterClassEscape] \s - -# 85| [RegExpPlus] \s+ -#-----| 0 -> [RegExpCharacterClassEscape] \s - -# 85| [RegExpSequence] \s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) -#-----| 0 -> [RegExpPlus] \s+ -#-----| 1 -> [RegExpGroup] (?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)) - -# 85| [RegExpCaret] ^ - -# 85| [RegExpSequence] ^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))? -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpOpt] (?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))? - -# 90| [RegExpConstant, RegExpNormalChar] - -# 90| [RegExpConstant, RegExpNormalChar] - -# 90| [RegExpConstant, RegExpNormalChar] - -# 90| [RegExpConstant, RegExpNormalChar] - -# 90| [RegExpStar] * -#-----| 0 -> [RegExpConstant, RegExpNormalChar] - -# 90| [RegExpStar] * -#-----| 0 -> [RegExpConstant, RegExpNormalChar] - -# 90| [RegExpStar] * -#-----| 0 -> [RegExpConstant, RegExpNormalChar] - -# 90| [RegExpDollar] $ - -# 90| [RegExpGroup] ((?:.*\|.*(?:\n|$))*) -#-----| 0 -> [RegExpStar] (?:.*\|.*(?:\n|$))* - -# 90| [RegExpGroup] (?:.*\|.*(?:\n|$)) -#-----| 0 -> [RegExpSequence] .*\|.*(?:\n|$) - -# 90| [RegExpStar] (?:.*\|.*(?:\n|$))* -#-----| 0 -> [RegExpGroup] (?:.*\|.*(?:\n|$)) - -# 90| [RegExpGroup] (?:\n|$) -#-----| 0 -> [RegExpAlt] \n|$ - -# 90| [RegExpGroup] ([-:]+ *\|[-| :]*) -#-----| 0 -> [RegExpSequence] [-:]+ *\|[-| :]* - -# 90| [RegExpGroup] (\S.*\|.*) -#-----| 0 -> [RegExpSequence] \S.*\|.* - -# 90| [RegExpConstant, RegExpNormalChar] - - -# 90| [RegExpConstant, RegExpNormalChar] - - -# 90| [RegExpDot] . - -# 90| [RegExpDot] . - -# 90| [RegExpDot] . - -# 90| [RegExpDot] . - -# 90| [RegExpStar] .* -#-----| 0 -> [RegExpDot] . - -# 90| [RegExpStar] .* -#-----| 0 -> [RegExpDot] . - -# 90| [RegExpStar] .* -#-----| 0 -> [RegExpDot] . - -# 90| [RegExpStar] .* -#-----| 0 -> [RegExpDot] . - -# 90| [RegExpSequence] .*\|.*(?:\n|$) -#-----| 0 -> [RegExpStar] .* -#-----| 1 -> [RegExpConstant, RegExpEscape] \| -#-----| 2 -> [RegExpStar] .* -#-----| 3 -> [RegExpGroup] (?:\n|$) - -# 90| [RegExpConstant, RegExpNormalChar] : - -# 90| [RegExpConstant, RegExpNormalChar] : - -# 90| [RegExpCharacterClass] [-:] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] - -#-----| 1 -> [RegExpConstant, RegExpNormalChar] : - -# 90| [RegExpPlus] [-:]+ -#-----| 0 -> [RegExpCharacterClass] [-:] - -# 90| [RegExpSequence] [-:]+ *\|[-| :]* -#-----| 0 -> [RegExpPlus] [-:]+ -#-----| 1 -> [RegExpStar] * -#-----| 2 -> [RegExpConstant, RegExpEscape] \| -#-----| 3 -> [RegExpStar] [-| :]* - -# 90| [RegExpCharacterClass] [-| :] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] - -#-----| 1 -> [RegExpConstant, RegExpNormalChar] | -#-----| 2 -> [RegExpConstant, RegExpNormalChar] -#-----| 3 -> [RegExpConstant, RegExpNormalChar] : - -# 90| [RegExpStar] [-| :]* -#-----| 0 -> [RegExpCharacterClass] [-| :] - -# 90| [RegExpCharacterClassEscape] \S - -# 90| [RegExpSequence] \S.*\|.* -#-----| 0 -> [RegExpCharacterClassEscape] \S -#-----| 1 -> [RegExpStar] .* -#-----| 2 -> [RegExpConstant, RegExpEscape] \| -#-----| 3 -> [RegExpStar] .* - -# 90| [RegExpConstant, RegExpEscape] \n - -# 90| [RegExpConstant, RegExpEscape] \n - -# 90| [RegExpConstant, RegExpEscape] \n - -# 90| [RegExpConstant, RegExpEscape] \n - -# 90| [RegExpStar] \n* -#-----| 0 -> [RegExpConstant, RegExpEscape] \n - -# 90| [RegExpAlt] \n|$ -#-----| 0 -> [RegExpConstant, RegExpEscape] \n -#-----| 1 -> [RegExpDollar] $ - -# 90| [RegExpConstant, RegExpEscape] \| - -# 90| [RegExpConstant, RegExpEscape] \| - -# 90| [RegExpConstant, RegExpEscape] \| - # 90| [RegExpCaret] ^ # 90| [RegExpSequence] ^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n* @@ -785,41 +663,129 @@ redos_variants.swift: #-----| 7 -> [RegExpGroup] ((?:.*\|.*(?:\n|$))*) #-----| 8 -> [RegExpStar] \n* +# 90| [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpStar] * +#-----| 0 -> [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpGroup] (\S.*\|.*) +#-----| 0 -> [RegExpSequence] \S.*\|.* + +# 90| [RegExpCharacterClassEscape] \S + +# 90| [RegExpSequence] \S.*\|.* +#-----| 0 -> [RegExpCharacterClassEscape] \S +#-----| 1 -> [RegExpStar] .* +#-----| 2 -> [RegExpConstant, RegExpEscape] \| +#-----| 3 -> [RegExpStar] .* + +# 90| [RegExpDot] . + +# 90| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 90| [RegExpConstant, RegExpEscape] \| + +# 90| [RegExpDot] . + +# 90| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 90| [RegExpConstant, RegExpEscape] \n + +# 90| [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpStar] * +#-----| 0 -> [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpGroup] ([-:]+ *\|[-| :]*) +#-----| 0 -> [RegExpSequence] [-:]+ *\|[-| :]* + +# 90| [RegExpCharacterClass] [-:] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] - +#-----| 1 -> [RegExpConstant, RegExpNormalChar] : + +# 90| [RegExpPlus] [-:]+ +#-----| 0 -> [RegExpCharacterClass] [-:] + +# 90| [RegExpSequence] [-:]+ *\|[-| :]* +#-----| 0 -> [RegExpPlus] [-:]+ +#-----| 1 -> [RegExpStar] * +#-----| 2 -> [RegExpConstant, RegExpEscape] \| +#-----| 3 -> [RegExpStar] [-| :]* + +# 90| [RegExpConstant, RegExpNormalChar] - + +# 90| [RegExpConstant, RegExpNormalChar] : + +# 90| [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpStar] * +#-----| 0 -> [RegExpConstant, RegExpNormalChar] + +# 90| [RegExpConstant, RegExpEscape] \| + +# 90| [RegExpCharacterClass] [-| :] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] - +#-----| 1 -> [RegExpConstant, RegExpNormalChar] | +#-----| 2 -> [RegExpConstant, RegExpNormalChar] +#-----| 3 -> [RegExpConstant, RegExpNormalChar] : + +# 90| [RegExpStar] [-| :]* +#-----| 0 -> [RegExpCharacterClass] [-| :] + +# 90| [RegExpConstant, RegExpNormalChar] - + # 90| [RegExpConstant, RegExpNormalChar] | -# 96| [RegExpConstant, RegExpNormalChar] +# 90| [RegExpConstant, RegExpNormalChar] -# 96| [RegExpDollar] $ +# 90| [RegExpConstant, RegExpNormalChar] : -# 96| [RegExpNegativeLookahead] (?![ *]) +# 90| [RegExpConstant, RegExpEscape] \n -# 96| [RegExpPositiveLookahead] (?=\W|$) +# 90| [RegExpGroup] ((?:.*\|.*(?:\n|$))*) +#-----| 0 -> [RegExpStar] (?:.*\|.*(?:\n|$))* -# 96| [RegExpGroup] (\\\/|.) -#-----| 0 -> [RegExpAlt] \\\/|. +# 90| [RegExpGroup] (?:.*\|.*(?:\n|$)) +#-----| 0 -> [RegExpSequence] .*\|.*(?:\n|$) -# 96| [RegExpStar] (\\\/|.)*? -#-----| 0 -> [RegExpGroup] (\\\/|.) +# 90| [RegExpStar] (?:.*\|.*(?:\n|$))* +#-----| 0 -> [RegExpGroup] (?:.*\|.*(?:\n|$)) -# 96| [RegExpConstant, RegExpNormalChar] * +# 90| [RegExpDot] . -# 96| [RegExpDot] . +# 90| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . -# 96| [RegExpCharacterClass] [ *] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] -#-----| 1 -> [RegExpConstant, RegExpNormalChar] * +# 90| [RegExpSequence] .*\|.*(?:\n|$) +#-----| 0 -> [RegExpStar] .* +#-----| 1 -> [RegExpConstant, RegExpEscape] \| +#-----| 2 -> [RegExpStar] .* +#-----| 3 -> [RegExpGroup] (?:\n|$) -# 96| [RegExpCharacterClass] [gim] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] g -#-----| 1 -> [RegExpConstant, RegExpNormalChar] i -#-----| 2 -> [RegExpConstant, RegExpNormalChar] m +# 90| [RegExpConstant, RegExpEscape] \| -# 96| [RegExpStar] [gim]* -#-----| 0 -> [RegExpCharacterClass] [gim] +# 90| [RegExpDot] . -# 96| [RegExpConstant, RegExpEscape] \/ +# 90| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . -# 96| [RegExpConstant, RegExpEscape] \/ +# 90| [RegExpGroup] (?:\n|$) +#-----| 0 -> [RegExpAlt] \n|$ + +# 90| [RegExpConstant, RegExpEscape] \n + +# 90| [RegExpAlt] \n|$ +#-----| 0 -> [RegExpConstant, RegExpEscape] \n +#-----| 1 -> [RegExpDollar] $ + +# 90| [RegExpDollar] $ + +# 90| [RegExpConstant, RegExpEscape] \n + +# 90| [RegExpStar] \n* +#-----| 0 -> [RegExpConstant, RegExpEscape] \n # 96| [RegExpConstant, RegExpEscape] \/ @@ -831,11 +797,21 @@ redos_variants.swift: #-----| 4 -> [RegExpStar] [gim]* #-----| 5 -> [RegExpPositiveLookahead] (?=\W|$) -# 96| [RegExpCharacterClassEscape] \W +# 96| [RegExpNegativeLookahead] (?![ *]) -# 96| [RegExpAlt] \W|$ -#-----| 0 -> [RegExpCharacterClassEscape] \W -#-----| 1 -> [RegExpDollar] $ +# 96| [RegExpCharacterClass] [ *] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] * + +# 96| [RegExpConstant, RegExpNormalChar] + +# 96| [RegExpConstant, RegExpNormalChar] * + +# 96| [RegExpGroup] (\\\/|.) +#-----| 0 -> [RegExpAlt] \\\/|. + +# 96| [RegExpStar] (\\\/|.)*? +#-----| 0 -> [RegExpGroup] (\\\/|.) # 96| [RegExpConstant, RegExpEscape] \\ @@ -847,19 +823,42 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] \\\/ #-----| 1 -> [RegExpDot] . +# 96| [RegExpConstant, RegExpEscape] \/ + +# 96| [RegExpDot] . + +# 96| [RegExpConstant, RegExpEscape] \/ + +# 96| [RegExpCharacterClass] [gim] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] g +#-----| 1 -> [RegExpConstant, RegExpNormalChar] i +#-----| 2 -> [RegExpConstant, RegExpNormalChar] m + +# 96| [RegExpStar] [gim]* +#-----| 0 -> [RegExpCharacterClass] [gim] + # 96| [RegExpConstant, RegExpNormalChar] g # 96| [RegExpConstant, RegExpNormalChar] i # 96| [RegExpConstant, RegExpNormalChar] m -# 102| [RegExpConstant, RegExpNormalChar] # +# 96| [RegExpPositiveLookahead] (?=\W|$) -# 102| [RegExpSequence] #.* -#-----| 0 -> [RegExpConstant, RegExpNormalChar] # -#-----| 1 -> [RegExpStar] .* +# 96| [RegExpCharacterClassEscape] \W -# 102| [RegExpDollar] $ +# 96| [RegExpAlt] \W|$ +#-----| 0 -> [RegExpCharacterClassEscape] \W +#-----| 1 -> [RegExpDollar] $ + +# 96| [RegExpDollar] $ + +# 102| [RegExpCaret] ^ + +# 102| [RegExpSequence] ^([\s\[\{\(]|#.*)*$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpStar] ([\s\[\{\(]|#.*)* +#-----| 2 -> [RegExpDollar] $ # 102| [RegExpGroup] ([\s\[\{\(]|#.*) #-----| 0 -> [RegExpAlt] [\s\[\{\(]|#.* @@ -867,11 +866,6 @@ redos_variants.swift: # 102| [RegExpStar] ([\s\[\{\(]|#.*)* #-----| 0 -> [RegExpGroup] ([\s\[\{\(]|#.*) -# 102| [RegExpDot] . - -# 102| [RegExpStar] .* -#-----| 0 -> [RegExpDot] . - # 102| [RegExpCharacterClass] [\s\[\{\(] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpConstant, RegExpEscape] \[ @@ -882,136 +876,26 @@ redos_variants.swift: #-----| 0 -> [RegExpCharacterClass] [\s\[\{\(] #-----| 1 -> [RegExpSequence] #.* -# 102| [RegExpConstant, RegExpEscape] \( +# 102| [RegExpCharacterClassEscape] \s # 102| [RegExpConstant, RegExpEscape] \[ -# 102| [RegExpCharacterClassEscape] \s - # 102| [RegExpConstant, RegExpEscape] \{ -# 102| [RegExpCaret] ^ +# 102| [RegExpConstant, RegExpEscape] \( -# 102| [RegExpSequence] ^([\s\[\{\(]|#.*)*$ -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpStar] ([\s\[\{\(]|#.*)* -#-----| 2 -> [RegExpDollar] $ +# 102| [RegExpConstant, RegExpNormalChar] # -# 108| [RegExpConstant, RegExpNormalChar] $ +# 102| [RegExpSequence] #.* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] # +#-----| 1 -> [RegExpStar] .* -# 108| [RegExpConstant, RegExpNormalChar] $ +# 102| [RegExpDot] . -# 108| [RegExpConstant, RegExpNormalChar] $ - -# 108| [RegExpConstant, RegExpNormalChar] $ - -# 108| [RegExpDollar] $ - -# 108| [RegExpGroup] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*) -#-----| 0 -> [RegExpSequence] \.[\_$a-z][\_$a-z0-9]*(\[.*?\])* - -# 108| [RegExpStar] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)* -#-----| 0 -> [RegExpGroup] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*) - -# 108| [RegExpGroup] (\[.*?\]) -#-----| 0 -> [RegExpSequence] \[.*?\] - -# 108| [RegExpGroup] (\[.*?\]) -#-----| 0 -> [RegExpSequence] \[.*?\] - -# 108| [RegExpStar] (\[.*?\])* -#-----| 0 -> [RegExpGroup] (\[.*?\]) - -# 108| [RegExpStar] (\[.*?\])* -#-----| 0 -> [RegExpGroup] (\[.*?\]) - -# 108| [RegExpDot] . - -# 108| [RegExpDot] . - -# 108| [RegExpStar] .*? +# 102| [RegExpStar] .* #-----| 0 -> [RegExpDot] . -# 108| [RegExpStar] .*? -#-----| 0 -> [RegExpDot] . - -# 108| [RegExpConstant, RegExpNormalChar] 0 - -# 108| [RegExpConstant, RegExpNormalChar] 0 - -# 108| [RegExpCharacterRange] 0-9 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 - -# 108| [RegExpCharacterRange] 0-9 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 - -# 108| [RegExpConstant, RegExpNormalChar] 9 - -# 108| [RegExpConstant, RegExpNormalChar] 9 - -# 108| [RegExpCharacterClass] [\_$a-z0-9] -#-----| 0 -> [RegExpConstant, RegExpEscape] \_ -#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ -#-----| 2 -> [RegExpCharacterRange] a-z -#-----| 3 -> [RegExpCharacterRange] 0-9 - -# 108| [RegExpCharacterClass] [\_$a-z0-9] -#-----| 0 -> [RegExpConstant, RegExpEscape] \_ -#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ -#-----| 2 -> [RegExpCharacterRange] a-z -#-----| 3 -> [RegExpCharacterRange] 0-9 - -# 108| [RegExpStar] [\_$a-z0-9]* -#-----| 0 -> [RegExpCharacterClass] [\_$a-z0-9] - -# 108| [RegExpStar] [\_$a-z0-9]* -#-----| 0 -> [RegExpCharacterClass] [\_$a-z0-9] - -# 108| [RegExpCharacterClass] [\_$a-z] -#-----| 0 -> [RegExpConstant, RegExpEscape] \_ -#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ -#-----| 2 -> [RegExpCharacterRange] a-z - -# 108| [RegExpCharacterClass] [\_$a-z] -#-----| 0 -> [RegExpConstant, RegExpEscape] \_ -#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ -#-----| 2 -> [RegExpCharacterRange] a-z - -# 108| [RegExpConstant, RegExpEscape] \. - -# 108| [RegExpSequence] \.[\_$a-z][\_$a-z0-9]*(\[.*?\])* -#-----| 0 -> [RegExpConstant, RegExpEscape] \. -#-----| 1 -> [RegExpCharacterClass] [\_$a-z] -#-----| 2 -> [RegExpStar] [\_$a-z0-9]* -#-----| 3 -> [RegExpStar] (\[.*?\])* - -# 108| [RegExpConstant, RegExpEscape] \[ - -# 108| [RegExpConstant, RegExpEscape] \[ - -# 108| [RegExpSequence] \[.*?\] -#-----| 0 -> [RegExpConstant, RegExpEscape] \[ -#-----| 1 -> [RegExpStar] .*? -#-----| 2 -> [RegExpConstant, RegExpEscape] \] - -# 108| [RegExpSequence] \[.*?\] -#-----| 0 -> [RegExpConstant, RegExpEscape] \[ -#-----| 1 -> [RegExpStar] .*? -#-----| 2 -> [RegExpConstant, RegExpEscape] \] - -# 108| [RegExpConstant, RegExpEscape] \] - -# 108| [RegExpConstant, RegExpEscape] \] - -# 108| [RegExpConstant, RegExpEscape] \_ - -# 108| [RegExpConstant, RegExpEscape] \_ - -# 108| [RegExpConstant, RegExpEscape] \_ - -# 108| [RegExpConstant, RegExpEscape] \_ +# 102| [RegExpDollar] $ # 108| [RegExpCaret] ^ @@ -1023,11 +907,14 @@ redos_variants.swift: #-----| 4 -> [RegExpStar] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)* #-----| 5 -> [RegExpDollar] $ -# 108| [RegExpConstant, RegExpNormalChar] a +# 108| [RegExpCharacterClass] [\_$a-z] +#-----| 0 -> [RegExpConstant, RegExpEscape] \_ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ +#-----| 2 -> [RegExpCharacterRange] a-z -# 108| [RegExpConstant, RegExpNormalChar] a +# 108| [RegExpConstant, RegExpEscape] \_ -# 108| [RegExpConstant, RegExpNormalChar] a +# 108| [RegExpConstant, RegExpNormalChar] $ # 108| [RegExpConstant, RegExpNormalChar] a @@ -1035,13 +922,22 @@ redos_variants.swift: #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpConstant, RegExpNormalChar] z -# 108| [RegExpCharacterRange] a-z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] z +# 108| [RegExpConstant, RegExpNormalChar] z -# 108| [RegExpCharacterRange] a-z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] z +# 108| [RegExpCharacterClass] [\_$a-z0-9] +#-----| 0 -> [RegExpConstant, RegExpEscape] \_ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ +#-----| 2 -> [RegExpCharacterRange] a-z +#-----| 3 -> [RegExpCharacterRange] 0-9 + +# 108| [RegExpStar] [\_$a-z0-9]* +#-----| 0 -> [RegExpCharacterClass] [\_$a-z0-9] + +# 108| [RegExpConstant, RegExpEscape] \_ + +# 108| [RegExpConstant, RegExpNormalChar] $ + +# 108| [RegExpConstant, RegExpNormalChar] a # 108| [RegExpCharacterRange] a-z #-----| 0 -> [RegExpConstant, RegExpNormalChar] a @@ -1049,17 +945,115 @@ redos_variants.swift: # 108| [RegExpConstant, RegExpNormalChar] z -# 108| [RegExpConstant, RegExpNormalChar] z +# 108| [RegExpConstant, RegExpNormalChar] 0 + +# 108| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 108| [RegExpConstant, RegExpNormalChar] 9 + +# 108| [RegExpGroup] (\[.*?\]) +#-----| 0 -> [RegExpSequence] \[.*?\] + +# 108| [RegExpStar] (\[.*?\])* +#-----| 0 -> [RegExpGroup] (\[.*?\]) + +# 108| [RegExpConstant, RegExpEscape] \[ + +# 108| [RegExpSequence] \[.*?\] +#-----| 0 -> [RegExpConstant, RegExpEscape] \[ +#-----| 1 -> [RegExpStar] .*? +#-----| 2 -> [RegExpConstant, RegExpEscape] \] + +# 108| [RegExpDot] . + +# 108| [RegExpStar] .*? +#-----| 0 -> [RegExpDot] . + +# 108| [RegExpConstant, RegExpEscape] \] + +# 108| [RegExpGroup] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*) +#-----| 0 -> [RegExpSequence] \.[\_$a-z][\_$a-z0-9]*(\[.*?\])* + +# 108| [RegExpStar] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)* +#-----| 0 -> [RegExpGroup] (\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*) + +# 108| [RegExpConstant, RegExpEscape] \. + +# 108| [RegExpSequence] \.[\_$a-z][\_$a-z0-9]*(\[.*?\])* +#-----| 0 -> [RegExpConstant, RegExpEscape] \. +#-----| 1 -> [RegExpCharacterClass] [\_$a-z] +#-----| 2 -> [RegExpStar] [\_$a-z0-9]* +#-----| 3 -> [RegExpStar] (\[.*?\])* + +# 108| [RegExpCharacterClass] [\_$a-z] +#-----| 0 -> [RegExpConstant, RegExpEscape] \_ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ +#-----| 2 -> [RegExpCharacterRange] a-z + +# 108| [RegExpConstant, RegExpEscape] \_ + +# 108| [RegExpConstant, RegExpNormalChar] $ + +# 108| [RegExpConstant, RegExpNormalChar] a + +# 108| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z # 108| [RegExpConstant, RegExpNormalChar] z +# 108| [RegExpCharacterClass] [\_$a-z0-9] +#-----| 0 -> [RegExpConstant, RegExpEscape] \_ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] $ +#-----| 2 -> [RegExpCharacterRange] a-z +#-----| 3 -> [RegExpCharacterRange] 0-9 + +# 108| [RegExpStar] [\_$a-z0-9]* +#-----| 0 -> [RegExpCharacterClass] [\_$a-z0-9] + +# 108| [RegExpConstant, RegExpEscape] \_ + +# 108| [RegExpConstant, RegExpNormalChar] $ + +# 108| [RegExpConstant, RegExpNormalChar] a + +# 108| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + # 108| [RegExpConstant, RegExpNormalChar] z -# 114| [RegExpConstant, RegExpNormalChar] # +# 108| [RegExpConstant, RegExpNormalChar] 0 -# 114| [RegExpDollar] $ +# 108| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 -# 114| [RegExpConstant, RegExpNormalChar] ( +# 108| [RegExpConstant, RegExpNormalChar] 9 + +# 108| [RegExpGroup] (\[.*?\]) +#-----| 0 -> [RegExpSequence] \[.*?\] + +# 108| [RegExpStar] (\[.*?\])* +#-----| 0 -> [RegExpGroup] (\[.*?\]) + +# 108| [RegExpConstant, RegExpEscape] \[ + +# 108| [RegExpSequence] \[.*?\] +#-----| 0 -> [RegExpConstant, RegExpEscape] \[ +#-----| 1 -> [RegExpStar] .*? +#-----| 2 -> [RegExpConstant, RegExpEscape] \] + +# 108| [RegExpDot] . + +# 108| [RegExpStar] .*? +#-----| 0 -> [RegExpDot] . + +# 108| [RegExpConstant, RegExpEscape] \] + +# 108| [RegExpDollar] $ # 114| [RegExpGroup] (([\w#:.~>+()\s-]+|\*|\[.*?\])+) #-----| 0 -> [RegExpPlus] ([\w#:.~>+()\s-]+|\*|\[.*?\])+ @@ -1069,38 +1063,12 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] \s* #-----| 2 -> [RegExpGroup] (,|$) -# 114| [RegExpGroup] (,|$) -#-----| 0 -> [RegExpAlt] ,|$ - # 114| [RegExpGroup] ([\w#:.~>+()\s-]+|\*|\[.*?\]) #-----| 0 -> [RegExpAlt] [\w#:.~>+()\s-]+|\*|\[.*?\] # 114| [RegExpPlus] ([\w#:.~>+()\s-]+|\*|\[.*?\])+ #-----| 0 -> [RegExpGroup] ([\w#:.~>+()\s-]+|\*|\[.*?\]) -# 114| [RegExpConstant, RegExpNormalChar] ) - -# 114| [RegExpConstant, RegExpNormalChar] + - -# 114| [RegExpConstant, RegExpNormalChar] , - -# 114| [RegExpAlt] ,|$ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] , -#-----| 1 -> [RegExpDollar] $ - -# 114| [RegExpConstant, RegExpNormalChar] - - -# 114| [RegExpConstant, RegExpNormalChar] . - -# 114| [RegExpDot] . - -# 114| [RegExpStar] .*? -#-----| 0 -> [RegExpDot] . - -# 114| [RegExpConstant, RegExpNormalChar] : - -# 114| [RegExpConstant, RegExpNormalChar] > - # 114| [RegExpCharacterClass] [\w#:.~>+()\s-] #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpNormalChar] # @@ -1122,6 +1090,28 @@ redos_variants.swift: #-----| 1 -> [RegExpConstant, RegExpEscape] \* #-----| 2 -> [RegExpSequence] \[.*?\] +# 114| [RegExpCharacterClassEscape] \w + +# 114| [RegExpConstant, RegExpNormalChar] # + +# 114| [RegExpConstant, RegExpNormalChar] : + +# 114| [RegExpConstant, RegExpNormalChar] . + +# 114| [RegExpConstant, RegExpNormalChar] ~ + +# 114| [RegExpConstant, RegExpNormalChar] > + +# 114| [RegExpConstant, RegExpNormalChar] + + +# 114| [RegExpConstant, RegExpNormalChar] ( + +# 114| [RegExpConstant, RegExpNormalChar] ) + +# 114| [RegExpCharacterClassEscape] \s + +# 114| [RegExpConstant, RegExpNormalChar] - + # 114| [RegExpConstant, RegExpEscape] \* # 114| [RegExpConstant, RegExpEscape] \[ @@ -1131,26 +1121,28 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] .*? #-----| 2 -> [RegExpConstant, RegExpEscape] \] -# 114| [RegExpConstant, RegExpEscape] \] +# 114| [RegExpDot] . -# 114| [RegExpCharacterClassEscape] \s +# 114| [RegExpStar] .*? +#-----| 0 -> [RegExpDot] . + +# 114| [RegExpConstant, RegExpEscape] \] # 114| [RegExpCharacterClassEscape] \s # 114| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s -# 114| [RegExpCharacterClassEscape] \w +# 114| [RegExpGroup] (,|$) +#-----| 0 -> [RegExpAlt] ,|$ -# 114| [RegExpConstant, RegExpNormalChar] ~ +# 114| [RegExpConstant, RegExpNormalChar] , -# 120| [RegExpConstant, RegExpNormalChar] " +# 114| [RegExpAlt] ,|$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] , +#-----| 1 -> [RegExpDollar] $ -# 120| [RegExpAlt] "|' -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " -#-----| 1 -> [RegExpConstant, RegExpNormalChar] ' - -# 120| [RegExpConstant, RegExpNormalChar] ' +# 114| [RegExpDollar] $ # 120| [RegExpGroup] ("|') #-----| 0 -> [RegExpAlt] "|' @@ -1160,16 +1152,20 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\\?.)*? #-----| 2 -> [RegExpBackRef] \1 +# 120| [RegExpConstant, RegExpNormalChar] " + +# 120| [RegExpAlt] "|' +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpConstant, RegExpNormalChar] ' + +# 120| [RegExpConstant, RegExpNormalChar] ' + # 120| [RegExpGroup] (\\?.) #-----| 0 -> [RegExpSequence] \\?. # 120| [RegExpStar] (\\?.)*? #-----| 0 -> [RegExpGroup] (\\?.) -# 120| [RegExpDot] . - -# 120| [RegExpBackRef] \1 - # 120| [RegExpConstant, RegExpEscape] \\ # 120| [RegExpOpt] \\? @@ -1179,18 +1175,16 @@ redos_variants.swift: #-----| 0 -> [RegExpOpt] \\? #-----| 1 -> [RegExpDot] . +# 120| [RegExpDot] . + +# 120| [RegExpBackRef] \1 + # 125| [RegExpGroup] (\r\n|\r|\n) #-----| 0 -> [RegExpAlt] \r\n|\r|\n # 125| [RegExpPlus] (\r\n|\r|\n)+ #-----| 0 -> [RegExpGroup] (\r\n|\r|\n) -# 125| [RegExpConstant, RegExpEscape] \n - -# 125| [RegExpConstant, RegExpEscape] \n - -# 125| [RegExpConstant, RegExpEscape] \r - # 125| [RegExpConstant, RegExpEscape] \r # 125| [RegExpSequence] \r\n @@ -1202,21 +1196,32 @@ redos_variants.swift: #-----| 1 -> [RegExpConstant, RegExpEscape] \r #-----| 2 -> [RegExpConstant, RegExpEscape] \n +# 125| [RegExpConstant, RegExpEscape] \n + +# 125| [RegExpConstant, RegExpEscape] \r + +# 125| [RegExpConstant, RegExpEscape] \n + # 128| [RegExpGroup] (a|.) #-----| 0 -> [RegExpAlt] a|. # 128| [RegExpStar] (a|.)* #-----| 0 -> [RegExpGroup] (a|.) -# 128| [RegExpDot] . - # 128| [RegExpConstant, RegExpNormalChar] a # 128| [RegExpAlt] a|. #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpDot] . -# 132| [RegExpDollar] $ +# 128| [RegExpDot] . + +# 132| [RegExpCaret] ^ + +# 132| [RegExpSequence] ^([a-z]+)+$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ([a-z]+)+ +#-----| 2 -> [RegExpDollar] $ # 132| [RegExpGroup] ([a-z]+) #-----| 0 -> [RegExpPlus] [a-z]+ @@ -1230,13 +1235,6 @@ redos_variants.swift: # 132| [RegExpPlus] [a-z]+ #-----| 0 -> [RegExpCharacterClass] [a-z] -# 132| [RegExpCaret] ^ - -# 132| [RegExpSequence] ^([a-z]+)+$ -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpPlus] ([a-z]+)+ -#-----| 2 -> [RegExpDollar] $ - # 132| [RegExpConstant, RegExpNormalChar] a # 132| [RegExpCharacterRange] a-z @@ -1245,7 +1243,14 @@ redos_variants.swift: # 132| [RegExpConstant, RegExpNormalChar] z -# 133| [RegExpDollar] $ +# 132| [RegExpDollar] $ + +# 133| [RegExpCaret] ^ + +# 133| [RegExpSequence] ^([a-z]*)*$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpStar] ([a-z]*)* +#-----| 2 -> [RegExpDollar] $ # 133| [RegExpGroup] ([a-z]*) #-----| 0 -> [RegExpStar] [a-z]* @@ -1259,13 +1264,6 @@ redos_variants.swift: # 133| [RegExpStar] [a-z]* #-----| 0 -> [RegExpCharacterClass] [a-z] -# 133| [RegExpCaret] ^ - -# 133| [RegExpSequence] ^([a-z]*)*$ -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpStar] ([a-z]*)* -#-----| 2 -> [RegExpDollar] $ - # 133| [RegExpConstant, RegExpNormalChar] a # 133| [RegExpCharacterRange] a-z @@ -1274,170 +1272,7 @@ redos_variants.swift: # 133| [RegExpConstant, RegExpNormalChar] z -# 134| [RegExpDollar] $ - -# 134| [RegExpGroup] (([\\.-]|[_]+)?([a-zA-Z0-9]+)) -#-----| 0 -> [RegExpSequence] ([\\.-]|[_]+)?([a-zA-Z0-9]+) - -# 134| [RegExpStar] (([\\.-]|[_]+)?([a-zA-Z0-9]+))* -#-----| 0 -> [RegExpGroup] (([\\.-]|[_]+)?([a-zA-Z0-9]+)) - -# 134| [RegExpGroup] (([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3})) -#-----| 0 -> [RegExpAlt] ([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}) - -# 134| [RegExpGroup] (@) -#-----| 0 -> [RegExpConstant, RegExpNormalChar] @ - -# 134| [RegExpRange] (@){1} -#-----| 0 -> [RegExpGroup] (@) - -# 134| [RegExpGroup] ([\\.-]|[_]+) -#-----| 0 -> [RegExpAlt] [\\.-]|[_]+ - -# 134| [RegExpOpt] ([\\.-]|[_]+)? -#-----| 0 -> [RegExpGroup] ([\\.-]|[_]+) - -# 134| [RegExpSequence] ([\\.-]|[_]+)?([a-zA-Z0-9]+) -#-----| 0 -> [RegExpOpt] ([\\.-]|[_]+)? -#-----| 1 -> [RegExpGroup] ([a-zA-Z0-9]+) - -# 134| [RegExpGroup] ([a-zA-Z0-9]) -#-----| 0 -> [RegExpCharacterClass] [a-zA-Z0-9] - -# 134| [RegExpGroup] ([a-zA-Z0-9]+) -#-----| 0 -> [RegExpPlus] [a-zA-Z0-9]+ - -# 134| [RegExpGroup] ([a-z]{2,3}) -#-----| 0 -> [RegExpRange] [a-z]{2,3} - -# 134| [RegExpAlt] ([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}) -#-----| 0 -> [RegExpGroup] ([a-z]{2,3}) -#-----| 1 -> [RegExpGroup] ([a-z]{2,3}[.]{1}[a-z]{2,3}) - -# 134| [RegExpGroup] ([a-z]{2,3}[.]{1}[a-z]{2,3}) -#-----| 0 -> [RegExpSequence] [a-z]{2,3}[.]{1}[a-z]{2,3} - -# 134| [RegExpConstant, RegExpNormalChar] - - -# 134| [RegExpConstant, RegExpNormalChar] . - -# 134| [RegExpConstant, RegExpNormalChar] . - -# 134| [RegExpConstant, RegExpNormalChar] . - -# 134| [RegExpConstant, RegExpNormalChar] 0 - -# 134| [RegExpConstant, RegExpNormalChar] 0 - -# 134| [RegExpConstant, RegExpNormalChar] 0 - -# 134| [RegExpCharacterRange] 0-9 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 - -# 134| [RegExpCharacterRange] 0-9 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 - -# 134| [RegExpCharacterRange] 0-9 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 - -# 134| [RegExpConstant, RegExpNormalChar] 9 - -# 134| [RegExpConstant, RegExpNormalChar] 9 - -# 134| [RegExpConstant, RegExpNormalChar] 9 - -# 134| [RegExpConstant, RegExpNormalChar] @ - -# 134| [RegExpConstant, RegExpNormalChar] A - -# 134| [RegExpConstant, RegExpNormalChar] A - -# 134| [RegExpCharacterRange] A-Z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] A -#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z - -# 134| [RegExpCharacterRange] A-Z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] A -#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z - -# 134| [RegExpConstant, RegExpNormalChar] Z - -# 134| [RegExpConstant, RegExpNormalChar] Z - -# 134| [RegExpCharacterClass] [.] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] . - -# 134| [RegExpCharacterClass] [.] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] . - -# 134| [RegExpRange] [.]{1} -#-----| 0 -> [RegExpCharacterClass] [.] - -# 134| [RegExpRange] [.]{1} -#-----| 0 -> [RegExpCharacterClass] [.] - -# 134| [RegExpCharacterClass] [\\.-] -#-----| 0 -> [RegExpConstant, RegExpEscape] \\ -#-----| 1 -> [RegExpConstant, RegExpNormalChar] . -#-----| 2 -> [RegExpConstant, RegExpNormalChar] - - -# 134| [RegExpAlt] [\\.-]|[_]+ -#-----| 0 -> [RegExpCharacterClass] [\\.-] -#-----| 1 -> [RegExpPlus] [_]+ - -# 134| [RegExpCharacterClass] [_] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] _ - -# 134| [RegExpPlus] [_]+ -#-----| 0 -> [RegExpCharacterClass] [_] - -# 134| [RegExpCharacterClass] [a-z0-9] -#-----| 0 -> [RegExpCharacterRange] a-z -#-----| 1 -> [RegExpCharacterRange] 0-9 - -# 134| [RegExpPlus] [a-z0-9]+ -#-----| 0 -> [RegExpCharacterClass] [a-z0-9] - -# 134| [RegExpCharacterClass] [a-zA-Z0-9] -#-----| 0 -> [RegExpCharacterRange] a-z -#-----| 1 -> [RegExpCharacterRange] A-Z -#-----| 2 -> [RegExpCharacterRange] 0-9 - -# 134| [RegExpCharacterClass] [a-zA-Z0-9] -#-----| 0 -> [RegExpCharacterRange] a-z -#-----| 1 -> [RegExpCharacterRange] A-Z -#-----| 2 -> [RegExpCharacterRange] 0-9 - -# 134| [RegExpPlus] [a-zA-Z0-9]+ -#-----| 0 -> [RegExpCharacterClass] [a-zA-Z0-9] - -# 134| [RegExpCharacterClass] [a-z] -#-----| 0 -> [RegExpCharacterRange] a-z - -# 134| [RegExpCharacterClass] [a-z] -#-----| 0 -> [RegExpCharacterRange] a-z - -# 134| [RegExpCharacterClass] [a-z] -#-----| 0 -> [RegExpCharacterRange] a-z - -# 134| [RegExpRange] [a-z]{2,3} -#-----| 0 -> [RegExpCharacterClass] [a-z] - -# 134| [RegExpRange] [a-z]{2,3} -#-----| 0 -> [RegExpCharacterClass] [a-z] - -# 134| [RegExpRange] [a-z]{2,3} -#-----| 0 -> [RegExpCharacterClass] [a-z] - -# 134| [RegExpSequence] [a-z]{2,3}[.]{1}[a-z]{2,3} -#-----| 0 -> [RegExpRange] [a-z]{2,3} -#-----| 1 -> [RegExpRange] [.]{1} -#-----| 2 -> [RegExpRange] [a-z]{2,3} - -# 134| [RegExpConstant, RegExpEscape] \\ +# 133| [RegExpDollar] $ # 134| [RegExpCaret] ^ @@ -1451,17 +1286,13 @@ redos_variants.swift: #-----| 6 -> [RegExpGroup] (([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3})) #-----| 7 -> [RegExpDollar] $ -# 134| [RegExpConstant, RegExpNormalChar] _ +# 134| [RegExpGroup] ([a-zA-Z0-9]) +#-----| 0 -> [RegExpCharacterClass] [a-zA-Z0-9] -# 134| [RegExpConstant, RegExpNormalChar] a - -# 134| [RegExpConstant, RegExpNormalChar] a - -# 134| [RegExpConstant, RegExpNormalChar] a - -# 134| [RegExpConstant, RegExpNormalChar] a - -# 134| [RegExpConstant, RegExpNormalChar] a +# 134| [RegExpCharacterClass] [a-zA-Z0-9] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z +#-----| 2 -> [RegExpCharacterRange] 0-9 # 134| [RegExpConstant, RegExpNormalChar] a @@ -1469,81 +1300,207 @@ redos_variants.swift: #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpConstant, RegExpNormalChar] z -# 134| [RegExpCharacterRange] a-z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] z - -# 134| [RegExpCharacterRange] a-z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] z - -# 134| [RegExpCharacterRange] a-z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] z - -# 134| [RegExpCharacterRange] a-z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] z - -# 134| [RegExpCharacterRange] a-z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] z - # 134| [RegExpConstant, RegExpNormalChar] z -# 134| [RegExpConstant, RegExpNormalChar] z +# 134| [RegExpConstant, RegExpNormalChar] A -# 134| [RegExpConstant, RegExpNormalChar] z - -# 134| [RegExpConstant, RegExpNormalChar] z - -# 134| [RegExpConstant, RegExpNormalChar] z - -# 134| [RegExpConstant, RegExpNormalChar] z - -# 135| [RegExpDollar] $ - -# 135| [RegExpGroup] (([a-z])+.) -#-----| 0 -> [RegExpSequence] ([a-z])+. - -# 135| [RegExpPlus] (([a-z])+.)+ -#-----| 0 -> [RegExpGroup] (([a-z])+.) - -# 135| [RegExpGroup] ([a-z]) -#-----| 0 -> [RegExpCharacterClass] [a-z] - -# 135| [RegExpGroup] ([a-z]) -#-----| 0 -> [RegExpCharacterClass] [a-z] - -# 135| [RegExpPlus] ([a-z])+ -#-----| 0 -> [RegExpGroup] ([a-z]) - -# 135| [RegExpPlus] ([a-z])+ -#-----| 0 -> [RegExpGroup] ([a-z]) - -# 135| [RegExpSequence] ([a-z])+. -#-----| 0 -> [RegExpPlus] ([a-z])+ -#-----| 1 -> [RegExpDot] . - -# 135| [RegExpDot] . - -# 135| [RegExpConstant, RegExpNormalChar] A - -# 135| [RegExpCharacterRange] A-Z +# 134| [RegExpCharacterRange] A-Z #-----| 0 -> [RegExpConstant, RegExpNormalChar] A #-----| 1 -> [RegExpConstant, RegExpNormalChar] Z -# 135| [RegExpConstant, RegExpNormalChar] Z +# 134| [RegExpConstant, RegExpNormalChar] Z -# 135| [RegExpCharacterClass] [A-Z] -#-----| 0 -> [RegExpCharacterRange] A-Z +# 134| [RegExpConstant, RegExpNormalChar] 0 -# 135| [RegExpCharacterClass] [a-z] +# 134| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpGroup] (([\\.-]|[_]+)?([a-zA-Z0-9]+)) +#-----| 0 -> [RegExpSequence] ([\\.-]|[_]+)?([a-zA-Z0-9]+) + +# 134| [RegExpStar] (([\\.-]|[_]+)?([a-zA-Z0-9]+))* +#-----| 0 -> [RegExpGroup] (([\\.-]|[_]+)?([a-zA-Z0-9]+)) + +# 134| [RegExpGroup] ([\\.-]|[_]+) +#-----| 0 -> [RegExpAlt] [\\.-]|[_]+ + +# 134| [RegExpOpt] ([\\.-]|[_]+)? +#-----| 0 -> [RegExpGroup] ([\\.-]|[_]+) + +# 134| [RegExpSequence] ([\\.-]|[_]+)?([a-zA-Z0-9]+) +#-----| 0 -> [RegExpOpt] ([\\.-]|[_]+)? +#-----| 1 -> [RegExpGroup] ([a-zA-Z0-9]+) + +# 134| [RegExpCharacterClass] [\\.-] +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] . +#-----| 2 -> [RegExpConstant, RegExpNormalChar] - + +# 134| [RegExpAlt] [\\.-]|[_]+ +#-----| 0 -> [RegExpCharacterClass] [\\.-] +#-----| 1 -> [RegExpPlus] [_]+ + +# 134| [RegExpConstant, RegExpEscape] \\ + +# 134| [RegExpConstant, RegExpNormalChar] . + +# 134| [RegExpConstant, RegExpNormalChar] - + +# 134| [RegExpCharacterClass] [_] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] _ + +# 134| [RegExpPlus] [_]+ +#-----| 0 -> [RegExpCharacterClass] [_] + +# 134| [RegExpConstant, RegExpNormalChar] _ + +# 134| [RegExpGroup] ([a-zA-Z0-9]+) +#-----| 0 -> [RegExpPlus] [a-zA-Z0-9]+ + +# 134| [RegExpCharacterClass] [a-zA-Z0-9] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z +#-----| 2 -> [RegExpCharacterRange] 0-9 + +# 134| [RegExpPlus] [a-zA-Z0-9]+ +#-----| 0 -> [RegExpCharacterClass] [a-zA-Z0-9] + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] A + +# 134| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 134| [RegExpConstant, RegExpNormalChar] Z + +# 134| [RegExpConstant, RegExpNormalChar] 0 + +# 134| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpGroup] (@) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] @ + +# 134| [RegExpRange] (@){1} +#-----| 0 -> [RegExpGroup] (@) + +# 134| [RegExpConstant, RegExpNormalChar] @ + +# 134| [RegExpCharacterClass] [a-z0-9] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] 0-9 + +# 134| [RegExpPlus] [a-z0-9]+ +#-----| 0 -> [RegExpCharacterClass] [a-z0-9] + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] 0 + +# 134| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpConstant, RegExpNormalChar] 9 + +# 134| [RegExpCharacterClass] [.] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] . + +# 134| [RegExpRange] [.]{1} +#-----| 0 -> [RegExpCharacterClass] [.] + +# 134| [RegExpConstant, RegExpNormalChar] . + +# 134| [RegExpGroup] (([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3})) +#-----| 0 -> [RegExpAlt] ([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}) + +# 134| [RegExpGroup] ([a-z]{2,3}) +#-----| 0 -> [RegExpRange] [a-z]{2,3} + +# 134| [RegExpAlt] ([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}) +#-----| 0 -> [RegExpGroup] ([a-z]{2,3}) +#-----| 1 -> [RegExpGroup] ([a-z]{2,3}[.]{1}[a-z]{2,3}) + +# 134| [RegExpCharacterClass] [a-z] #-----| 0 -> [RegExpCharacterRange] a-z -# 135| [RegExpCharacterClass] [a-z] +# 134| [RegExpRange] [a-z]{2,3} +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpGroup] ([a-z]{2,3}[.]{1}[a-z]{2,3}) +#-----| 0 -> [RegExpSequence] [a-z]{2,3}[.]{1}[a-z]{2,3} + +# 134| [RegExpCharacterClass] [a-z] #-----| 0 -> [RegExpCharacterRange] a-z +# 134| [RegExpRange] [a-z]{2,3} +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 134| [RegExpSequence] [a-z]{2,3}[.]{1}[a-z]{2,3} +#-----| 0 -> [RegExpRange] [a-z]{2,3} +#-----| 1 -> [RegExpRange] [.]{1} +#-----| 2 -> [RegExpRange] [a-z]{2,3} + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpCharacterClass] [.] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] . + +# 134| [RegExpRange] [.]{1} +#-----| 0 -> [RegExpCharacterClass] [.] + +# 134| [RegExpConstant, RegExpNormalChar] . + +# 134| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 134| [RegExpRange] [a-z]{2,3} +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 134| [RegExpConstant, RegExpNormalChar] a + +# 134| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpConstant, RegExpNormalChar] z + +# 134| [RegExpDollar] $ + # 135| [RegExpCaret] ^ # 135| [RegExpSequence] ^(([a-z])+.)+[A-Z]([a-z])+$ @@ -1553,7 +1510,24 @@ redos_variants.swift: #-----| 3 -> [RegExpPlus] ([a-z])+ #-----| 4 -> [RegExpDollar] $ -# 135| [RegExpConstant, RegExpNormalChar] a +# 135| [RegExpGroup] (([a-z])+.) +#-----| 0 -> [RegExpSequence] ([a-z])+. + +# 135| [RegExpPlus] (([a-z])+.)+ +#-----| 0 -> [RegExpGroup] (([a-z])+.) + +# 135| [RegExpGroup] ([a-z]) +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 135| [RegExpPlus] ([a-z])+ +#-----| 0 -> [RegExpGroup] ([a-z]) + +# 135| [RegExpSequence] ([a-z])+. +#-----| 0 -> [RegExpPlus] ([a-z])+ +#-----| 1 -> [RegExpDot] . + +# 135| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z # 135| [RegExpConstant, RegExpNormalChar] a @@ -1561,13 +1535,39 @@ redos_variants.swift: #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpConstant, RegExpNormalChar] z +# 135| [RegExpConstant, RegExpNormalChar] z + +# 135| [RegExpDot] . + +# 135| [RegExpCharacterClass] [A-Z] +#-----| 0 -> [RegExpCharacterRange] A-Z + +# 135| [RegExpConstant, RegExpNormalChar] A + +# 135| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 135| [RegExpConstant, RegExpNormalChar] Z + +# 135| [RegExpGroup] ([a-z]) +#-----| 0 -> [RegExpCharacterClass] [a-z] + +# 135| [RegExpPlus] ([a-z])+ +#-----| 0 -> [RegExpGroup] ([a-z]) + +# 135| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 135| [RegExpConstant, RegExpNormalChar] a + # 135| [RegExpCharacterRange] a-z #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpConstant, RegExpNormalChar] z # 135| [RegExpConstant, RegExpNormalChar] z -# 135| [RegExpConstant, RegExpNormalChar] z +# 135| [RegExpDollar] $ # 139| [RegExpGroup] (b|a?b) #-----| 0 -> [RegExpAlt] b|a?b @@ -1579,6 +1579,12 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] (b|a?b)* #-----| 1 -> [RegExpConstant, RegExpNormalChar] c +# 139| [RegExpConstant, RegExpNormalChar] b + +# 139| [RegExpAlt] b|a?b +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b +#-----| 1 -> [RegExpSequence] a?b + # 139| [RegExpConstant, RegExpNormalChar] a # 139| [RegExpOpt] a? @@ -1590,16 +1596,8 @@ redos_variants.swift: # 139| [RegExpConstant, RegExpNormalChar] b -# 139| [RegExpConstant, RegExpNormalChar] b - -# 139| [RegExpAlt] b|a?b -#-----| 0 -> [RegExpConstant, RegExpNormalChar] b -#-----| 1 -> [RegExpSequence] a?b - # 139| [RegExpConstant, RegExpNormalChar] c -# 142| [RegExpConstant, RegExpNormalChar] ! - # 142| [RegExpGroup] (.|\n) #-----| 0 -> [RegExpAlt] .|\n @@ -1618,7 +1616,9 @@ redos_variants.swift: # 142| [RegExpConstant, RegExpEscape] \n -# 146| [RegExpConstant, RegExpNormalChar] ! +# 142| [RegExpConstant, RegExpNormalChar] ! + +# 146| [RegExpConstant, RegExpNormalChar] s # 146| [RegExpGroup] (.|\n) #-----| 0 -> [RegExpAlt] .|\n @@ -1634,7 +1634,7 @@ redos_variants.swift: # 146| [RegExpConstant, RegExpEscape] \n -# 146| [RegExpConstant, RegExpNormalChar] s +# 146| [RegExpConstant, RegExpNormalChar] ! # 149| [RegExpGroup] ([\w.]+) #-----| 0 -> [RegExpPlus] [\w.]+ @@ -1642,8 +1642,6 @@ redos_variants.swift: # 149| [RegExpStar] ([\w.]+)* #-----| 0 -> [RegExpGroup] ([\w.]+) -# 149| [RegExpConstant, RegExpNormalChar] . - # 149| [RegExpCharacterClass] [\w.] #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpNormalChar] . @@ -1653,14 +1651,14 @@ redos_variants.swift: # 149| [RegExpCharacterClassEscape] \w +# 149| [RegExpConstant, RegExpNormalChar] . + # 152| [RegExpGroup] ([\w.]+) #-----| 0 -> [RegExpPlus] [\w.]+ # 152| [RegExpStar] ([\w.]+)* #-----| 0 -> [RegExpGroup] ([\w.]+) -# 152| [RegExpConstant, RegExpNormalChar] . - # 152| [RegExpCharacterClass] [\w.] #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpNormalChar] . @@ -1670,7 +1668,7 @@ redos_variants.swift: # 152| [RegExpCharacterClassEscape] \w -# 156| [RegExpConstant, RegExpNormalChar] " +# 152| [RegExpConstant, RegExpNormalChar] . # 156| [RegExpGroup] (([\s\S]|[^a])*) #-----| 0 -> [RegExpStar] ([\s\S]|[^a])* @@ -1693,18 +1691,16 @@ redos_variants.swift: #-----| 0 -> [RegExpCharacterClass] [\s\S] #-----| 1 -> [RegExpCharacterClass] [^a] -# 156| [RegExpCharacterClass] [^a] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +# 156| [RegExpCharacterClassEscape] \s # 156| [RegExpCharacterClassEscape] \S -# 156| [RegExpCharacterClassEscape] \s +# 156| [RegExpCharacterClass] [^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a # 156| [RegExpConstant, RegExpNormalChar] a -# 159| [RegExpConstant, RegExpNormalChar] " - -# 159| [RegExpConstant, RegExpNormalChar] ' +# 156| [RegExpConstant, RegExpNormalChar] " # 159| [RegExpGroup] ([^"']+) #-----| 0 -> [RegExpPlus] [^"']+ @@ -1719,7 +1715,9 @@ redos_variants.swift: # 159| [RegExpPlus] [^"']+ #-----| 0 -> [RegExpCharacterClass] [^"'] -# 163| [RegExpConstant, RegExpNormalChar] " +# 159| [RegExpConstant, RegExpNormalChar] " + +# 159| [RegExpConstant, RegExpNormalChar] ' # 163| [RegExpGroup] ((.|[^a])*) #-----| 0 -> [RegExpStar] (.|[^a])* @@ -1745,7 +1743,7 @@ redos_variants.swift: # 163| [RegExpConstant, RegExpNormalChar] a -# 166| [RegExpConstant, RegExpNormalChar] " +# 163| [RegExpConstant, RegExpNormalChar] " # 166| [RegExpGroup] ((a|[^a])*) #-----| 0 -> [RegExpStar] (a|[^a])* @@ -1760,18 +1758,18 @@ redos_variants.swift: # 166| [RegExpStar] (a|[^a])* #-----| 0 -> [RegExpGroup] (a|[^a]) -# 166| [RegExpCharacterClass] [^a] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a - -# 166| [RegExpConstant, RegExpNormalChar] a - # 166| [RegExpConstant, RegExpNormalChar] a # 166| [RegExpAlt] a|[^a] #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpCharacterClass] [^a] -# 170| [RegExpConstant, RegExpNormalChar] " +# 166| [RegExpCharacterClass] [^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 166| [RegExpConstant, RegExpNormalChar] a + +# 166| [RegExpConstant, RegExpNormalChar] " # 170| [RegExpGroup] ((b|[^a])*) #-----| 0 -> [RegExpStar] (b|[^a])* @@ -1786,18 +1784,18 @@ redos_variants.swift: # 170| [RegExpStar] (b|[^a])* #-----| 0 -> [RegExpGroup] (b|[^a]) -# 170| [RegExpCharacterClass] [^a] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a - -# 170| [RegExpConstant, RegExpNormalChar] a - # 170| [RegExpConstant, RegExpNormalChar] b # 170| [RegExpAlt] b|[^a] #-----| 0 -> [RegExpConstant, RegExpNormalChar] b #-----| 1 -> [RegExpCharacterClass] [^a] -# 174| [RegExpConstant, RegExpNormalChar] " +# 170| [RegExpCharacterClass] [^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 170| [RegExpConstant, RegExpNormalChar] a + +# 170| [RegExpConstant, RegExpNormalChar] " # 174| [RegExpGroup] ((G|[^a])*) #-----| 0 -> [RegExpStar] (G|[^a])* @@ -1823,7 +1821,7 @@ redos_variants.swift: # 174| [RegExpConstant, RegExpNormalChar] a -# 178| [RegExpConstant, RegExpNormalChar] " +# 174| [RegExpConstant, RegExpNormalChar] " # 178| [RegExpGroup] (([0-9]|[^a])*) #-----| 0 -> [RegExpStar] ([0-9]|[^a])* @@ -1838,6 +1836,13 @@ redos_variants.swift: # 178| [RegExpStar] ([0-9]|[^a])* #-----| 0 -> [RegExpGroup] ([0-9]|[^a]) +# 178| [RegExpCharacterClass] [0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 178| [RegExpAlt] [0-9]|[^a] +#-----| 0 -> [RegExpCharacterClass] [0-9] +#-----| 1 -> [RegExpCharacterClass] [^a] + # 178| [RegExpConstant, RegExpNormalChar] 0 # 178| [RegExpCharacterRange] 0-9 @@ -1846,44 +1851,12 @@ redos_variants.swift: # 178| [RegExpConstant, RegExpNormalChar] 9 -# 178| [RegExpCharacterClass] [0-9] -#-----| 0 -> [RegExpCharacterRange] 0-9 - -# 178| [RegExpAlt] [0-9]|[^a] -#-----| 0 -> [RegExpCharacterClass] [0-9] -#-----| 1 -> [RegExpCharacterClass] [^a] - # 178| [RegExpCharacterClass] [^a] #-----| 0 -> [RegExpConstant, RegExpNormalChar] a # 178| [RegExpConstant, RegExpNormalChar] a -# 182| [RegExpConstant, RegExpNormalChar] ! - -# 182| [RegExpConstant, RegExpNormalChar] " - -# 182| [RegExpConstant, RegExpNormalChar] " - -# 182| [RegExpConstant, RegExpNormalChar] " - -# 182| [RegExpSequence] "((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)" -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " -#-----| 1 -> [RegExpGroup] ((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*) -#-----| 2 -> [RegExpConstant, RegExpNormalChar] " - -# 182| [RegExpConstant, RegExpNormalChar] # - -# 182| [RegExpConstant, RegExpNormalChar] % - -# 182| [RegExpConstant, RegExpNormalChar] & - -# 182| [RegExpConstant, RegExpNormalChar] ' - -# 182| [RegExpGroup] ((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*) -#-----| 0 -> [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])* - -# 182| [RegExpGroup] (?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") -#-----| 0 -> [RegExpAlt] ([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)" +# 178| [RegExpConstant, RegExpNormalChar] " # 182| [RegExpGroup] (?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)")) #-----| 0 -> [RegExpSequence] =(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") @@ -1891,11 +1864,14 @@ redos_variants.swift: # 182| [RegExpOpt] (?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"))? #-----| 0 -> [RegExpGroup] (?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)")) -# 182| [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"]) -#-----| 0 -> [RegExpAlt] \\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"] +# 182| [RegExpConstant, RegExpNormalChar] = -# 182| [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])* -#-----| 0 -> [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"]) +# 182| [RegExpSequence] =(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") +#-----| 0 -> [RegExpConstant, RegExpNormalChar] = +#-----| 1 -> [RegExpGroup] (?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") + +# 182| [RegExpGroup] (?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") +#-----| 0 -> [RegExpAlt] ([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)" # 182| [RegExpGroup] ([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) #-----| 0 -> [RegExpPlus] [!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+ @@ -1904,28 +1880,6 @@ redos_variants.swift: #-----| 0 -> [RegExpGroup] ([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) #-----| 1 -> [RegExpSequence] "((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)" -# 182| [RegExpConstant, RegExpNormalChar] 0 - -# 182| [RegExpCharacterRange] 0-9 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 - -# 182| [RegExpConstant, RegExpNormalChar] 9 - -# 182| [RegExpConstant, RegExpNormalChar] = - -# 182| [RegExpSequence] =(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") -#-----| 0 -> [RegExpConstant, RegExpNormalChar] = -#-----| 1 -> [RegExpGroup] (?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)") - -# 182| [RegExpConstant, RegExpNormalChar] A - -# 182| [RegExpCharacterRange] A-Z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] A -#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z - -# 182| [RegExpConstant, RegExpNormalChar] Z - # 182| [RegExpCharacterClass] [!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z] #-----| 0 -> [RegExpConstant, RegExpNormalChar] ! #-----| 1 -> [RegExpConstant, RegExpNormalChar] # @@ -1949,17 +1903,18 @@ redos_variants.swift: # 182| [RegExpPlus] [!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+ #-----| 0 -> [RegExpCharacterClass] [!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z] -# 182| [RegExpCharacterClass] [\x00-\x7f] -#-----| 0 -> [RegExpCharacterRange] \x00-\x7f +# 182| [RegExpConstant, RegExpNormalChar] ! -# 182| [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"] -#-----| 0 -> [RegExpCharacterRange] \x00-\x08 -#-----| 1 -> [RegExpCharacterRange] \x0a-\x1f -#-----| 2 -> [RegExpConstant, RegExpEscape] \x7f -#-----| 3 -> [RegExpConstant, RegExpNormalChar] " +# 182| [RegExpConstant, RegExpNormalChar] # # 182| [RegExpConstant, RegExpEscape] \$ +# 182| [RegExpConstant, RegExpNormalChar] % + +# 182| [RegExpConstant, RegExpNormalChar] & + +# 182| [RegExpConstant, RegExpNormalChar] ' + # 182| [RegExpConstant, RegExpEscape] \* # 182| [RegExpConstant, RegExpEscape] \+ @@ -1968,6 +1923,56 @@ redos_variants.swift: # 182| [RegExpConstant, RegExpEscape] \. +# 182| [RegExpConstant, RegExpEscape] \^ + +# 182| [RegExpConstant, RegExpNormalChar] _ + +# 182| [RegExpConstant, RegExpNormalChar] ` + +# 182| [RegExpConstant, RegExpEscape] \| + +# 182| [RegExpConstant, RegExpNormalChar] ~ + +# 182| [RegExpConstant, RegExpNormalChar] 0 + +# 182| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 182| [RegExpConstant, RegExpNormalChar] 9 + +# 182| [RegExpConstant, RegExpNormalChar] A + +# 182| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 182| [RegExpConstant, RegExpNormalChar] Z + +# 182| [RegExpConstant, RegExpNormalChar] a + +# 182| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 182| [RegExpConstant, RegExpNormalChar] z + +# 182| [RegExpConstant, RegExpNormalChar] " + +# 182| [RegExpSequence] "((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpGroup] ((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*) +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 182| [RegExpGroup] ((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*) +#-----| 0 -> [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])* + +# 182| [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"]) +#-----| 0 -> [RegExpAlt] \\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"] + +# 182| [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])* +#-----| 0 -> [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"]) + # 182| [RegExpConstant, RegExpEscape] \\ # 182| [RegExpSequence] \\[\x00-\x7f] @@ -1978,20 +1983,29 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] \\[\x00-\x7f] #-----| 1 -> [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"] -# 182| [RegExpConstant, RegExpEscape] \^ +# 182| [RegExpCharacterClass] [\x00-\x7f] +#-----| 0 -> [RegExpCharacterRange] \x00-\x7f # 182| [RegExpConstant, RegExpEscape] \x00 +# 182| [RegExpCharacterRange] \x00-\x7f +#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 +#-----| 1 -> [RegExpConstant, RegExpEscape] \x7f + +# 182| [RegExpConstant, RegExpEscape] \x7f + +# 182| [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"] +#-----| 0 -> [RegExpCharacterRange] \x00-\x08 +#-----| 1 -> [RegExpCharacterRange] \x0a-\x1f +#-----| 2 -> [RegExpConstant, RegExpEscape] \x7f +#-----| 3 -> [RegExpConstant, RegExpNormalChar] " + # 182| [RegExpConstant, RegExpEscape] \x00 # 182| [RegExpCharacterRange] \x00-\x08 #-----| 0 -> [RegExpConstant, RegExpEscape] \x00 #-----| 1 -> [RegExpConstant, RegExpEscape] \x08 -# 182| [RegExpCharacterRange] \x00-\x7f -#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 -#-----| 1 -> [RegExpConstant, RegExpEscape] \x7f - # 182| [RegExpConstant, RegExpEscape] \x08 # 182| [RegExpConstant, RegExpEscape] \x0a @@ -2004,27 +2018,9 @@ redos_variants.swift: # 182| [RegExpConstant, RegExpEscape] \x7f -# 182| [RegExpConstant, RegExpEscape] \x7f +# 182| [RegExpConstant, RegExpNormalChar] " -# 182| [RegExpConstant, RegExpEscape] \| - -# 182| [RegExpConstant, RegExpNormalChar] _ - -# 182| [RegExpConstant, RegExpNormalChar] ` - -# 182| [RegExpConstant, RegExpNormalChar] a - -# 182| [RegExpCharacterRange] a-z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] z - -# 182| [RegExpConstant, RegExpNormalChar] z - -# 182| [RegExpConstant, RegExpNormalChar] ~ - -# 186| [RegExpConstant, RegExpNormalChar] " - -# 186| [RegExpConstant, RegExpNormalChar] " +# 182| [RegExpConstant, RegExpNormalChar] " # 186| [RegExpConstant, RegExpNormalChar] " @@ -2042,15 +2038,6 @@ redos_variants.swift: # 186| [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])* #-----| 0 -> [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"]) -# 186| [RegExpCharacterClass] [\x00-\x7f] -#-----| 0 -> [RegExpCharacterRange] \x00-\x7f - -# 186| [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"] -#-----| 0 -> [RegExpCharacterRange] \x00-\x08 -#-----| 1 -> [RegExpCharacterRange] \x0a-\x1f -#-----| 2 -> [RegExpConstant, RegExpEscape] \x7f -#-----| 3 -> [RegExpConstant, RegExpNormalChar] " - # 186| [RegExpConstant, RegExpEscape] \\ # 186| [RegExpSequence] \\[\x00-\x7f] @@ -2061,18 +2048,29 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] \\[\x00-\x7f] #-----| 1 -> [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"] +# 186| [RegExpCharacterClass] [\x00-\x7f] +#-----| 0 -> [RegExpCharacterRange] \x00-\x7f + # 186| [RegExpConstant, RegExpEscape] \x00 +# 186| [RegExpCharacterRange] \x00-\x7f +#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 +#-----| 1 -> [RegExpConstant, RegExpEscape] \x7f + +# 186| [RegExpConstant, RegExpEscape] \x7f + +# 186| [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"] +#-----| 0 -> [RegExpCharacterRange] \x00-\x08 +#-----| 1 -> [RegExpCharacterRange] \x0a-\x1f +#-----| 2 -> [RegExpConstant, RegExpEscape] \x7f +#-----| 3 -> [RegExpConstant, RegExpNormalChar] " + # 186| [RegExpConstant, RegExpEscape] \x00 # 186| [RegExpCharacterRange] \x00-\x08 #-----| 0 -> [RegExpConstant, RegExpEscape] \x00 #-----| 1 -> [RegExpConstant, RegExpEscape] \x08 -# 186| [RegExpCharacterRange] \x00-\x7f -#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 -#-----| 1 -> [RegExpConstant, RegExpEscape] \x7f - # 186| [RegExpConstant, RegExpEscape] \x08 # 186| [RegExpConstant, RegExpEscape] \x0a @@ -2085,11 +2083,9 @@ redos_variants.swift: # 186| [RegExpConstant, RegExpEscape] \x7f -# 186| [RegExpConstant, RegExpEscape] \x7f +# 186| [RegExpConstant, RegExpNormalChar] " -# 189| [RegExpConstant, RegExpNormalChar] " - -# 189| [RegExpConstant, RegExpNormalChar] " +# 186| [RegExpConstant, RegExpNormalChar] " # 189| [RegExpConstant, RegExpNormalChar] " @@ -2107,18 +2103,6 @@ redos_variants.swift: # 189| [RegExpStar] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])* #-----| 0 -> [RegExpGroup] (?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\]) -# 189| [RegExpCharacterClass] [\x00-\x7f] -#-----| 0 -> [RegExpCharacterRange] \x00-\x7f - -# 189| [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"\\] -#-----| 0 -> [RegExpCharacterRange] \x00-\x08 -#-----| 1 -> [RegExpCharacterRange] \x0a-\x1f -#-----| 2 -> [RegExpConstant, RegExpEscape] \x7f -#-----| 3 -> [RegExpConstant, RegExpNormalChar] " -#-----| 4 -> [RegExpConstant, RegExpEscape] \\ - -# 189| [RegExpConstant, RegExpEscape] \\ - # 189| [RegExpConstant, RegExpEscape] \\ # 189| [RegExpSequence] \\[\x00-\x7f] @@ -2129,18 +2113,30 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] \\[\x00-\x7f] #-----| 1 -> [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"\\] +# 189| [RegExpCharacterClass] [\x00-\x7f] +#-----| 0 -> [RegExpCharacterRange] \x00-\x7f + # 189| [RegExpConstant, RegExpEscape] \x00 +# 189| [RegExpCharacterRange] \x00-\x7f +#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 +#-----| 1 -> [RegExpConstant, RegExpEscape] \x7f + +# 189| [RegExpConstant, RegExpEscape] \x7f + +# 189| [RegExpCharacterClass] [^\x00-\x08\x0a-\x1f\x7f"\\] +#-----| 0 -> [RegExpCharacterRange] \x00-\x08 +#-----| 1 -> [RegExpCharacterRange] \x0a-\x1f +#-----| 2 -> [RegExpConstant, RegExpEscape] \x7f +#-----| 3 -> [RegExpConstant, RegExpNormalChar] " +#-----| 4 -> [RegExpConstant, RegExpEscape] \\ + # 189| [RegExpConstant, RegExpEscape] \x00 # 189| [RegExpCharacterRange] \x00-\x08 #-----| 0 -> [RegExpConstant, RegExpEscape] \x00 #-----| 1 -> [RegExpConstant, RegExpEscape] \x08 -# 189| [RegExpCharacterRange] \x00-\x7f -#-----| 0 -> [RegExpConstant, RegExpEscape] \x00 -#-----| 1 -> [RegExpConstant, RegExpEscape] \x7f - # 189| [RegExpConstant, RegExpEscape] \x08 # 189| [RegExpConstant, RegExpEscape] \x0a @@ -2153,9 +2149,11 @@ redos_variants.swift: # 189| [RegExpConstant, RegExpEscape] \x7f -# 189| [RegExpConstant, RegExpEscape] \x7f +# 189| [RegExpConstant, RegExpNormalChar] " -# 193| [RegExpConstant, RegExpNormalChar] " +# 189| [RegExpConstant, RegExpEscape] \\ + +# 189| [RegExpConstant, RegExpNormalChar] " # 193| [RegExpGroup] (([a-z]|[d-h])*) #-----| 0 -> [RegExpStar] ([a-z]|[d-h])* @@ -2177,15 +2175,17 @@ redos_variants.swift: #-----| 0 -> [RegExpCharacterClass] [a-z] #-----| 1 -> [RegExpCharacterClass] [d-h] -# 193| [RegExpCharacterClass] [d-h] -#-----| 0 -> [RegExpCharacterRange] d-h - # 193| [RegExpConstant, RegExpNormalChar] a # 193| [RegExpCharacterRange] a-z #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpConstant, RegExpNormalChar] z +# 193| [RegExpConstant, RegExpNormalChar] z + +# 193| [RegExpCharacterClass] [d-h] +#-----| 0 -> [RegExpCharacterRange] d-h + # 193| [RegExpConstant, RegExpNormalChar] d # 193| [RegExpCharacterRange] d-h @@ -2194,9 +2194,7 @@ redos_variants.swift: # 193| [RegExpConstant, RegExpNormalChar] h -# 193| [RegExpConstant, RegExpNormalChar] z - -# 197| [RegExpConstant, RegExpNormalChar] " +# 193| [RegExpConstant, RegExpNormalChar] " # 197| [RegExpGroup] (([^a-z]|[^0-9])*) #-----| 0 -> [RegExpStar] ([^a-z]|[^0-9])* @@ -2211,17 +2209,6 @@ redos_variants.swift: # 197| [RegExpStar] ([^a-z]|[^0-9])* #-----| 0 -> [RegExpGroup] ([^a-z]|[^0-9]) -# 197| [RegExpConstant, RegExpNormalChar] 0 - -# 197| [RegExpCharacterRange] 0-9 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 - -# 197| [RegExpConstant, RegExpNormalChar] 9 - -# 197| [RegExpCharacterClass] [^0-9] -#-----| 0 -> [RegExpCharacterRange] 0-9 - # 197| [RegExpCharacterClass] [^a-z] #-----| 0 -> [RegExpCharacterRange] a-z @@ -2237,7 +2224,18 @@ redos_variants.swift: # 197| [RegExpConstant, RegExpNormalChar] z -# 201| [RegExpConstant, RegExpNormalChar] " +# 197| [RegExpCharacterClass] [^0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 197| [RegExpConstant, RegExpNormalChar] 0 + +# 197| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 197| [RegExpConstant, RegExpNormalChar] 9 + +# 197| [RegExpConstant, RegExpNormalChar] " # 201| [RegExpGroup] ((\d|[0-9])*) #-----| 0 -> [RegExpStar] (\d|[0-9])* @@ -2252,6 +2250,15 @@ redos_variants.swift: # 201| [RegExpStar] (\d|[0-9])* #-----| 0 -> [RegExpGroup] (\d|[0-9]) +# 201| [RegExpCharacterClassEscape] \d + +# 201| [RegExpAlt] \d|[0-9] +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpCharacterClass] [0-9] + +# 201| [RegExpCharacterClass] [0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + # 201| [RegExpConstant, RegExpNormalChar] 0 # 201| [RegExpCharacterRange] 0-9 @@ -2260,16 +2267,7 @@ redos_variants.swift: # 201| [RegExpConstant, RegExpNormalChar] 9 -# 201| [RegExpCharacterClass] [0-9] -#-----| 0 -> [RegExpCharacterRange] 0-9 - -# 201| [RegExpCharacterClassEscape] \d - -# 201| [RegExpAlt] \d|[0-9] -#-----| 0 -> [RegExpCharacterClassEscape] \d -#-----| 1 -> [RegExpCharacterClass] [0-9] - -# 205| [RegExpConstant, RegExpNormalChar] " +# 201| [RegExpConstant, RegExpNormalChar] " # 205| [RegExpGroup] ((\s|\s)*) #-----| 0 -> [RegExpStar] (\s|\s)* @@ -2286,13 +2284,13 @@ redos_variants.swift: # 205| [RegExpCharacterClassEscape] \s -# 205| [RegExpCharacterClassEscape] \s - # 205| [RegExpAlt] \s|\s #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \s -# 209| [RegExpConstant, RegExpNormalChar] " +# 205| [RegExpCharacterClassEscape] \s + +# 205| [RegExpConstant, RegExpNormalChar] " # 209| [RegExpGroup] ((\w|G)*) #-----| 0 -> [RegExpStar] (\w|G)* @@ -2307,15 +2305,15 @@ redos_variants.swift: # 209| [RegExpStar] (\w|G)* #-----| 0 -> [RegExpGroup] (\w|G) -# 209| [RegExpConstant, RegExpNormalChar] G - # 209| [RegExpCharacterClassEscape] \w # 209| [RegExpAlt] \w|G #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpNormalChar] G -# 212| [RegExpConstant, RegExpNormalChar] " +# 209| [RegExpConstant, RegExpNormalChar] G + +# 209| [RegExpConstant, RegExpNormalChar] " # 212| [RegExpGroup] ((\s|\d)*) #-----| 0 -> [RegExpStar] (\s|\d)* @@ -2330,15 +2328,15 @@ redos_variants.swift: # 212| [RegExpStar] (\s|\d)* #-----| 0 -> [RegExpGroup] (\s|\d) -# 212| [RegExpCharacterClassEscape] \d - # 212| [RegExpCharacterClassEscape] \s # 212| [RegExpAlt] \s|\d #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \d -# 216| [RegExpConstant, RegExpNormalChar] " +# 212| [RegExpCharacterClassEscape] \d + +# 212| [RegExpConstant, RegExpNormalChar] " # 216| [RegExpGroup] ((\d|\d)*) #-----| 0 -> [RegExpStar] (\d|\d)* @@ -2355,13 +2353,13 @@ redos_variants.swift: # 216| [RegExpCharacterClassEscape] \d -# 216| [RegExpCharacterClassEscape] \d - # 216| [RegExpAlt] \d|\d #-----| 0 -> [RegExpCharacterClassEscape] \d #-----| 1 -> [RegExpCharacterClassEscape] \d -# 220| [RegExpConstant, RegExpNormalChar] " +# 216| [RegExpCharacterClassEscape] \d + +# 216| [RegExpConstant, RegExpNormalChar] " # 220| [RegExpGroup] ((\d|\w)*) #-----| 0 -> [RegExpStar] (\d|\w)* @@ -2384,7 +2382,7 @@ redos_variants.swift: # 220| [RegExpCharacterClassEscape] \w -# 224| [RegExpConstant, RegExpNormalChar] " +# 220| [RegExpConstant, RegExpNormalChar] " # 224| [RegExpGroup] ((\d|5)*) #-----| 0 -> [RegExpStar] (\d|5)* @@ -2399,15 +2397,15 @@ redos_variants.swift: # 224| [RegExpStar] (\d|5)* #-----| 0 -> [RegExpGroup] (\d|5) -# 224| [RegExpConstant, RegExpNormalChar] 5 - # 224| [RegExpCharacterClassEscape] \d # 224| [RegExpAlt] \d|5 #-----| 0 -> [RegExpCharacterClassEscape] \d #-----| 1 -> [RegExpConstant, RegExpNormalChar] 5 -# 228| [RegExpConstant, RegExpNormalChar] " +# 224| [RegExpConstant, RegExpNormalChar] 5 + +# 224| [RegExpConstant, RegExpNormalChar] " # 228| [RegExpGroup] ((\s|[\f])*) #-----| 0 -> [RegExpStar] (\s|[\f])* @@ -2422,18 +2420,18 @@ redos_variants.swift: # 228| [RegExpStar] (\s|[\f])* #-----| 0 -> [RegExpGroup] (\s|[\f]) -# 228| [RegExpCharacterClass] [\f] -#-----| 0 -> [RegExpConstant, RegExpEscape] \f - -# 228| [RegExpConstant, RegExpEscape] \f - # 228| [RegExpCharacterClassEscape] \s # 228| [RegExpAlt] \s|[\f] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClass] [\f] -# 232| [RegExpConstant, RegExpNormalChar] " +# 228| [RegExpCharacterClass] [\f] +#-----| 0 -> [RegExpConstant, RegExpEscape] \f + +# 228| [RegExpConstant, RegExpEscape] \f + +# 228| [RegExpConstant, RegExpNormalChar] " # 232| [RegExpGroup] ((\s|[\v]|\\v)*) #-----| 0 -> [RegExpStar] (\s|[\v]|\\v)* @@ -2448,15 +2446,6 @@ redos_variants.swift: # 232| [RegExpStar] (\s|[\v]|\\v)* #-----| 0 -> [RegExpGroup] (\s|[\v]|\\v) -# 232| [RegExpCharacterClass] [\v] -#-----| 0 -> [RegExpConstant, RegExpEscape] \v - -# 232| [RegExpConstant, RegExpEscape] \\ - -# 232| [RegExpSequence] \\v -#-----| 0 -> [RegExpConstant, RegExpEscape] \\ -#-----| 1 -> [RegExpConstant, RegExpNormalChar] v - # 232| [RegExpCharacterClassEscape] \s # 232| [RegExpAlt] \s|[\v]|\\v @@ -2464,11 +2453,20 @@ redos_variants.swift: #-----| 1 -> [RegExpCharacterClass] [\v] #-----| 2 -> [RegExpSequence] \\v +# 232| [RegExpCharacterClass] [\v] +#-----| 0 -> [RegExpConstant, RegExpEscape] \v + # 232| [RegExpConstant, RegExpEscape] \v +# 232| [RegExpConstant, RegExpEscape] \\ + +# 232| [RegExpSequence] \\v +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] v + # 232| [RegExpConstant, RegExpNormalChar] v -# 236| [RegExpConstant, RegExpNormalChar] " +# 232| [RegExpConstant, RegExpNormalChar] " # 236| [RegExpGroup] ((\f|[\f])*) #-----| 0 -> [RegExpStar] (\f|[\f])* @@ -2483,18 +2481,18 @@ redos_variants.swift: # 236| [RegExpStar] (\f|[\f])* #-----| 0 -> [RegExpGroup] (\f|[\f]) -# 236| [RegExpCharacterClass] [\f] -#-----| 0 -> [RegExpConstant, RegExpEscape] \f - -# 236| [RegExpConstant, RegExpEscape] \f - # 236| [RegExpConstant, RegExpEscape] \f # 236| [RegExpAlt] \f|[\f] #-----| 0 -> [RegExpConstant, RegExpEscape] \f #-----| 1 -> [RegExpCharacterClass] [\f] -# 240| [RegExpConstant, RegExpNormalChar] " +# 236| [RegExpCharacterClass] [\f] +#-----| 0 -> [RegExpConstant, RegExpEscape] \f + +# 236| [RegExpConstant, RegExpEscape] \f + +# 236| [RegExpConstant, RegExpNormalChar] " # 240| [RegExpGroup] ((\W|\D)*) #-----| 0 -> [RegExpStar] (\W|\D)* @@ -2509,15 +2507,15 @@ redos_variants.swift: # 240| [RegExpStar] (\W|\D)* #-----| 0 -> [RegExpGroup] (\W|\D) -# 240| [RegExpCharacterClassEscape] \D - # 240| [RegExpCharacterClassEscape] \W # 240| [RegExpAlt] \W|\D #-----| 0 -> [RegExpCharacterClassEscape] \W #-----| 1 -> [RegExpCharacterClassEscape] \D -# 244| [RegExpConstant, RegExpNormalChar] " +# 240| [RegExpCharacterClassEscape] \D + +# 240| [RegExpConstant, RegExpNormalChar] " # 244| [RegExpGroup] ((\S|\w)*) #-----| 0 -> [RegExpStar] (\S|\w)* @@ -2540,7 +2538,7 @@ redos_variants.swift: # 244| [RegExpCharacterClassEscape] \w -# 248| [RegExpConstant, RegExpNormalChar] " +# 244| [RegExpConstant, RegExpNormalChar] " # 248| [RegExpGroup] ((\S|[\w])*) #-----| 0 -> [RegExpStar] (\S|[\w])* @@ -2555,18 +2553,18 @@ redos_variants.swift: # 248| [RegExpStar] (\S|[\w])* #-----| 0 -> [RegExpGroup] (\S|[\w]) -# 248| [RegExpCharacterClass] [\w] -#-----| 0 -> [RegExpCharacterClassEscape] \w - # 248| [RegExpCharacterClassEscape] \S # 248| [RegExpAlt] \S|[\w] #-----| 0 -> [RegExpCharacterClassEscape] \S #-----| 1 -> [RegExpCharacterClass] [\w] +# 248| [RegExpCharacterClass] [\w] +#-----| 0 -> [RegExpCharacterClassEscape] \w + # 248| [RegExpCharacterClassEscape] \w -# 252| [RegExpConstant, RegExpNormalChar] " +# 248| [RegExpConstant, RegExpNormalChar] " # 252| [RegExpGroup] ((1s|[\da-z])*) #-----| 0 -> [RegExpStar] (1s|[\da-z])* @@ -2601,7 +2599,7 @@ redos_variants.swift: # 252| [RegExpConstant, RegExpNormalChar] z -# 256| [RegExpConstant, RegExpNormalChar] " +# 252| [RegExpConstant, RegExpNormalChar] " # 256| [RegExpGroup] ((0|[\d])*) #-----| 0 -> [RegExpStar] (0|[\d])* @@ -2627,7 +2625,7 @@ redos_variants.swift: # 256| [RegExpCharacterClassEscape] \d -# 260| [RegExpConstant, RegExpNormalChar] " +# 256| [RegExpConstant, RegExpNormalChar] " # 260| [RegExpGroup] (([\d]+)*) #-----| 0 -> [RegExpStar] ([\d]+)* @@ -2650,11 +2648,7 @@ redos_variants.swift: # 260| [RegExpCharacterClassEscape] \d -# 263| [RegExpGroup] (X\d+) -#-----| 0 -> [RegExpSequence] X\d+ - -# 263| [RegExpOpt] (X\d+)? -#-----| 0 -> [RegExpGroup] (X\d+) +# 260| [RegExpConstant, RegExpNormalChar] " # 263| [RegExpGroup] (\d+(X\d+)?) #-----| 0 -> [RegExpSequence] \d+(X\d+)? @@ -2662,6 +2656,21 @@ redos_variants.swift: # 263| [RegExpPlus] (\d+(X\d+)?)+ #-----| 0 -> [RegExpGroup] (\d+(X\d+)?) +# 263| [RegExpCharacterClassEscape] \d + +# 263| [RegExpPlus] \d+ +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 263| [RegExpSequence] \d+(X\d+)? +#-----| 0 -> [RegExpPlus] \d+ +#-----| 1 -> [RegExpOpt] (X\d+)? + +# 263| [RegExpGroup] (X\d+) +#-----| 0 -> [RegExpSequence] X\d+ + +# 263| [RegExpOpt] (X\d+)? +#-----| 0 -> [RegExpGroup] (X\d+) + # 263| [RegExpConstant, RegExpNormalChar] X # 263| [RegExpSequence] X\d+ @@ -2670,15 +2679,21 @@ redos_variants.swift: # 263| [RegExpCharacterClassEscape] \d -# 263| [RegExpCharacterClassEscape] \d - # 263| [RegExpPlus] \d+ #-----| 0 -> [RegExpCharacterClassEscape] \d -# 263| [RegExpPlus] \d+ +# 266| [RegExpGroup] (\d+(X\d+)?) +#-----| 0 -> [RegExpSequence] \d+(X\d+)? + +# 266| [RegExpPlus] (\d+(X\d+)?)+ +#-----| 0 -> [RegExpGroup] (\d+(X\d+)?) + +# 266| [RegExpCharacterClassEscape] \d + +# 266| [RegExpPlus] \d+ #-----| 0 -> [RegExpCharacterClassEscape] \d -# 263| [RegExpSequence] \d+(X\d+)? +# 266| [RegExpSequence] \d+(X\d+)? #-----| 0 -> [RegExpPlus] \d+ #-----| 1 -> [RegExpOpt] (X\d+)? @@ -2688,12 +2703,6 @@ redos_variants.swift: # 266| [RegExpOpt] (X\d+)? #-----| 0 -> [RegExpGroup] (X\d+) -# 266| [RegExpGroup] (\d+(X\d+)?) -#-----| 0 -> [RegExpSequence] \d+(X\d+)? - -# 266| [RegExpPlus] (\d+(X\d+)?)+ -#-----| 0 -> [RegExpGroup] (\d+(X\d+)?) - # 266| [RegExpConstant, RegExpNormalChar] X # 266| [RegExpSequence] X\d+ @@ -2702,31 +2711,24 @@ redos_variants.swift: # 266| [RegExpCharacterClassEscape] \d -# 266| [RegExpCharacterClassEscape] \d - # 266| [RegExpPlus] \d+ #-----| 0 -> [RegExpCharacterClassEscape] \d -# 266| [RegExpPlus] \d+ -#-----| 0 -> [RegExpCharacterClassEscape] \d - -# 266| [RegExpSequence] \d+(X\d+)? -#-----| 0 -> [RegExpPlus] \d+ -#-----| 1 -> [RegExpOpt] (X\d+)? - -# 269| [RegExpGroup] (X[0-9]*) -#-----| 0 -> [RegExpSequence] X[0-9]* - -# 269| [RegExpOpt] (X[0-9]*)? -#-----| 0 -> [RegExpGroup] (X[0-9]*) - # 269| [RegExpGroup] ([0-9]+(X[0-9]*)?) #-----| 0 -> [RegExpSequence] [0-9]+(X[0-9]*)? # 269| [RegExpStar] ([0-9]+(X[0-9]*)?)* #-----| 0 -> [RegExpGroup] ([0-9]+(X[0-9]*)?) -# 269| [RegExpConstant, RegExpNormalChar] 0 +# 269| [RegExpCharacterClass] [0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 269| [RegExpPlus] [0-9]+ +#-----| 0 -> [RegExpCharacterClass] [0-9] + +# 269| [RegExpSequence] [0-9]+(X[0-9]*)? +#-----| 0 -> [RegExpPlus] [0-9]+ +#-----| 1 -> [RegExpOpt] (X[0-9]*)? # 269| [RegExpConstant, RegExpNormalChar] 0 @@ -2734,13 +2736,13 @@ redos_variants.swift: #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 -# 269| [RegExpCharacterRange] 0-9 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 - # 269| [RegExpConstant, RegExpNormalChar] 9 -# 269| [RegExpConstant, RegExpNormalChar] 9 +# 269| [RegExpGroup] (X[0-9]*) +#-----| 0 -> [RegExpSequence] X[0-9]* + +# 269| [RegExpOpt] (X[0-9]*)? +#-----| 0 -> [RegExpGroup] (X[0-9]*) # 269| [RegExpConstant, RegExpNormalChar] X @@ -2751,24 +2753,16 @@ redos_variants.swift: # 269| [RegExpCharacterClass] [0-9] #-----| 0 -> [RegExpCharacterRange] 0-9 -# 269| [RegExpCharacterClass] [0-9] -#-----| 0 -> [RegExpCharacterRange] 0-9 - # 269| [RegExpStar] [0-9]* #-----| 0 -> [RegExpCharacterClass] [0-9] -# 269| [RegExpPlus] [0-9]+ -#-----| 0 -> [RegExpCharacterClass] [0-9] +# 269| [RegExpConstant, RegExpNormalChar] 0 -# 269| [RegExpSequence] [0-9]+(X[0-9]*)? -#-----| 0 -> [RegExpPlus] [0-9]+ -#-----| 1 -> [RegExpOpt] (X[0-9]*)? +# 269| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 -# 272| [RegExpGroup] (X[0-9]*) -#-----| 0 -> [RegExpSequence] X[0-9]* - -# 272| [RegExpOpt] (X[0-9]*)? -#-----| 0 -> [RegExpGroup] (X[0-9]*) +# 269| [RegExpConstant, RegExpNormalChar] 9 # 272| [RegExpGroup] ([0-9]+(X[0-9]*)?) #-----| 0 -> [RegExpSequence] [0-9]+(X[0-9]*)? @@ -2776,7 +2770,15 @@ redos_variants.swift: # 272| [RegExpStar] ([0-9]+(X[0-9]*)?)* #-----| 0 -> [RegExpGroup] ([0-9]+(X[0-9]*)?) -# 272| [RegExpConstant, RegExpNormalChar] 0 +# 272| [RegExpCharacterClass] [0-9] +#-----| 0 -> [RegExpCharacterRange] 0-9 + +# 272| [RegExpPlus] [0-9]+ +#-----| 0 -> [RegExpCharacterClass] [0-9] + +# 272| [RegExpSequence] [0-9]+(X[0-9]*)? +#-----| 0 -> [RegExpPlus] [0-9]+ +#-----| 1 -> [RegExpOpt] (X[0-9]*)? # 272| [RegExpConstant, RegExpNormalChar] 0 @@ -2784,13 +2786,13 @@ redos_variants.swift: #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 -# 272| [RegExpCharacterRange] 0-9 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 - # 272| [RegExpConstant, RegExpNormalChar] 9 -# 272| [RegExpConstant, RegExpNormalChar] 9 +# 272| [RegExpGroup] (X[0-9]*) +#-----| 0 -> [RegExpSequence] X[0-9]* + +# 272| [RegExpOpt] (X[0-9]*)? +#-----| 0 -> [RegExpGroup] (X[0-9]*) # 272| [RegExpConstant, RegExpNormalChar] X @@ -2801,43 +2803,16 @@ redos_variants.swift: # 272| [RegExpCharacterClass] [0-9] #-----| 0 -> [RegExpCharacterRange] 0-9 -# 272| [RegExpCharacterClass] [0-9] -#-----| 0 -> [RegExpCharacterRange] 0-9 - # 272| [RegExpStar] [0-9]* #-----| 0 -> [RegExpCharacterClass] [0-9] -# 272| [RegExpPlus] [0-9]+ -#-----| 0 -> [RegExpCharacterClass] [0-9] +# 272| [RegExpConstant, RegExpNormalChar] 0 -# 272| [RegExpSequence] [0-9]+(X[0-9]*)? -#-----| 0 -> [RegExpPlus] [0-9]+ -#-----| 1 -> [RegExpOpt] (X[0-9]*)? +# 272| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 -# 275| [RegExpDollar] $ - -# 275| [RegExpGroup] (>|$) -#-----| 0 -> [RegExpAlt] >|$ - -# 275| [RegExpGroup] ([^>]+) -#-----| 0 -> [RegExpPlus] [^>]+ - -# 275| [RegExpStar] ([^>]+)* -#-----| 0 -> [RegExpGroup] ([^>]+) - -# 275| [RegExpConstant, RegExpNormalChar] > - -# 275| [RegExpConstant, RegExpNormalChar] > - -# 275| [RegExpAlt] >|$ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] > -#-----| 1 -> [RegExpDollar] $ - -# 275| [RegExpCharacterClass] [^>] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] > - -# 275| [RegExpPlus] [^>]+ -#-----| 0 -> [RegExpCharacterClass] [^>] +# 272| [RegExpConstant, RegExpNormalChar] 9 # 275| [RegExpCaret] ^ @@ -2846,31 +2821,30 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] ([^>]+)* #-----| 2 -> [RegExpGroup] (>|$) -# 279| [RegExpDollar] $ +# 275| [RegExpGroup] ([^>]+) +#-----| 0 -> [RegExpPlus] [^>]+ -# 279| [RegExpGroup] (>|$) +# 275| [RegExpStar] ([^>]+)* +#-----| 0 -> [RegExpGroup] ([^>]+) + +# 275| [RegExpCharacterClass] [^>] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] > + +# 275| [RegExpPlus] [^>]+ +#-----| 0 -> [RegExpCharacterClass] [^>] + +# 275| [RegExpConstant, RegExpNormalChar] > + +# 275| [RegExpGroup] (>|$) #-----| 0 -> [RegExpAlt] >|$ -# 279| [RegExpGroup] ([^>a]+) -#-----| 0 -> [RegExpPlus] [^>a]+ +# 275| [RegExpConstant, RegExpNormalChar] > -# 279| [RegExpStar] ([^>a]+)* -#-----| 0 -> [RegExpGroup] ([^>a]+) - -# 279| [RegExpConstant, RegExpNormalChar] > - -# 279| [RegExpConstant, RegExpNormalChar] > - -# 279| [RegExpAlt] >|$ +# 275| [RegExpAlt] >|$ #-----| 0 -> [RegExpConstant, RegExpNormalChar] > #-----| 1 -> [RegExpDollar] $ -# 279| [RegExpCharacterClass] [^>a] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] > -#-----| 1 -> [RegExpConstant, RegExpNormalChar] a - -# 279| [RegExpPlus] [^>a]+ -#-----| 0 -> [RegExpCharacterClass] [^>a] +# 275| [RegExpDollar] $ # 279| [RegExpCaret] ^ @@ -2879,9 +2853,33 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] ([^>a]+)* #-----| 2 -> [RegExpGroup] (>|$) +# 279| [RegExpGroup] ([^>a]+) +#-----| 0 -> [RegExpPlus] [^>a]+ + +# 279| [RegExpStar] ([^>a]+)* +#-----| 0 -> [RegExpGroup] ([^>a]+) + +# 279| [RegExpCharacterClass] [^>a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] > +#-----| 1 -> [RegExpConstant, RegExpNormalChar] a + +# 279| [RegExpPlus] [^>a]+ +#-----| 0 -> [RegExpCharacterClass] [^>a] + +# 279| [RegExpConstant, RegExpNormalChar] > + # 279| [RegExpConstant, RegExpNormalChar] a -# 283| [RegExpDollar] $ +# 279| [RegExpGroup] (>|$) +#-----| 0 -> [RegExpAlt] >|$ + +# 279| [RegExpConstant, RegExpNormalChar] > + +# 279| [RegExpAlt] >|$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] > +#-----| 1 -> [RegExpDollar] $ + +# 279| [RegExpDollar] $ # 283| [RegExpGroup] (\n\s*) #-----| 0 -> [RegExpSequence] \n\s* @@ -2904,22 +2902,14 @@ redos_variants.swift: # 283| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s -# 287| [RegExpConstant, RegExpNormalChar] # +# 283| [RegExpDollar] $ -# 287| [RegExpConstant, RegExpNormalChar] # +# 287| [RegExpCaret] ^ -# 287| [RegExpSequence] #.* -#-----| 0 -> [RegExpConstant, RegExpNormalChar] # -#-----| 1 -> [RegExpStar] .* - -# 287| [RegExpGroup] (?:,\d*) -#-----| 0 -> [RegExpSequence] ,\d* - -# 287| [RegExpOpt] (?:,\d*)? -#-----| 0 -> [RegExpGroup] (?:,\d*) - -# 287| [RegExpGroup] (?:[?*+]|\{\d+(?:,\d*)?}) -#-----| 0 -> [RegExpAlt] [?*+]|\{\d+(?:,\d*)?} +# 287| [RegExpSequence] ^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|\{\d+(?:,\d*)?}) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpStar] (?:\s+|#.*|\(\?#[^)]*\))* +#-----| 2 -> [RegExpGroup] (?:[?*+]|\{\d+(?:,\d*)?}) # 287| [RegExpGroup] (?:\s+|#.*|\(\?#[^)]*\)) #-----| 0 -> [RegExpAlt] \s+|#.*|\(\?#[^)]*\) @@ -2927,63 +2917,6 @@ redos_variants.swift: # 287| [RegExpStar] (?:\s+|#.*|\(\?#[^)]*\))* #-----| 0 -> [RegExpGroup] (?:\s+|#.*|\(\?#[^)]*\)) -# 287| [RegExpConstant, RegExpNormalChar] ) - -# 287| [RegExpConstant, RegExpNormalChar] * - -# 287| [RegExpConstant, RegExpNormalChar] + - -# 287| [RegExpConstant, RegExpNormalChar] , - -# 287| [RegExpSequence] ,\d* -#-----| 0 -> [RegExpConstant, RegExpNormalChar] , -#-----| 1 -> [RegExpStar] \d* - -# 287| [RegExpDot] . - -# 287| [RegExpStar] .* -#-----| 0 -> [RegExpDot] . - -# 287| [RegExpConstant, RegExpNormalChar] ? - -# 287| [RegExpCharacterClass] [?*+] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] ? -#-----| 1 -> [RegExpConstant, RegExpNormalChar] * -#-----| 2 -> [RegExpConstant, RegExpNormalChar] + - -# 287| [RegExpAlt] [?*+]|\{\d+(?:,\d*)?} -#-----| 0 -> [RegExpCharacterClass] [?*+] -#-----| 1 -> [RegExpSequence] \{\d+(?:,\d*)?} - -# 287| [RegExpCharacterClass] [^)] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] ) - -# 287| [RegExpStar] [^)]* -#-----| 0 -> [RegExpCharacterClass] [^)] - -# 287| [RegExpConstant, RegExpEscape] \( - -# 287| [RegExpSequence] \(\?#[^)]*\) -#-----| 0 -> [RegExpConstant, RegExpEscape] \( -#-----| 1 -> [RegExpConstant, RegExpEscape] \? -#-----| 2 -> [RegExpConstant, RegExpNormalChar] # -#-----| 3 -> [RegExpStar] [^)]* -#-----| 4 -> [RegExpConstant, RegExpEscape] \) - -# 287| [RegExpConstant, RegExpEscape] \) - -# 287| [RegExpConstant, RegExpEscape] \? - -# 287| [RegExpCharacterClassEscape] \d - -# 287| [RegExpCharacterClassEscape] \d - -# 287| [RegExpStar] \d* -#-----| 0 -> [RegExpCharacterClassEscape] \d - -# 287| [RegExpPlus] \d+ -#-----| 0 -> [RegExpCharacterClassEscape] \d - # 287| [RegExpCharacterClassEscape] \s # 287| [RegExpPlus] \s+ @@ -2994,6 +2927,58 @@ redos_variants.swift: #-----| 1 -> [RegExpSequence] #.* #-----| 2 -> [RegExpSequence] \(\?#[^)]*\) +# 287| [RegExpConstant, RegExpNormalChar] # + +# 287| [RegExpSequence] #.* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] # +#-----| 1 -> [RegExpStar] .* + +# 287| [RegExpDot] . + +# 287| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 287| [RegExpConstant, RegExpEscape] \( + +# 287| [RegExpSequence] \(\?#[^)]*\) +#-----| 0 -> [RegExpConstant, RegExpEscape] \( +#-----| 1 -> [RegExpConstant, RegExpEscape] \? +#-----| 2 -> [RegExpConstant, RegExpNormalChar] # +#-----| 3 -> [RegExpStar] [^)]* +#-----| 4 -> [RegExpConstant, RegExpEscape] \) + +# 287| [RegExpConstant, RegExpEscape] \? + +# 287| [RegExpConstant, RegExpNormalChar] # + +# 287| [RegExpCharacterClass] [^)] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ) + +# 287| [RegExpStar] [^)]* +#-----| 0 -> [RegExpCharacterClass] [^)] + +# 287| [RegExpConstant, RegExpNormalChar] ) + +# 287| [RegExpConstant, RegExpEscape] \) + +# 287| [RegExpGroup] (?:[?*+]|\{\d+(?:,\d*)?}) +#-----| 0 -> [RegExpAlt] [?*+]|\{\d+(?:,\d*)?} + +# 287| [RegExpCharacterClass] [?*+] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ? +#-----| 1 -> [RegExpConstant, RegExpNormalChar] * +#-----| 2 -> [RegExpConstant, RegExpNormalChar] + + +# 287| [RegExpAlt] [?*+]|\{\d+(?:,\d*)?} +#-----| 0 -> [RegExpCharacterClass] [?*+] +#-----| 1 -> [RegExpSequence] \{\d+(?:,\d*)?} + +# 287| [RegExpConstant, RegExpNormalChar] ? + +# 287| [RegExpConstant, RegExpNormalChar] * + +# 287| [RegExpConstant, RegExpNormalChar] + + # 287| [RegExpConstant, RegExpEscape] \{ # 287| [RegExpSequence] \{\d+(?:,\d*)?} @@ -3002,147 +2987,30 @@ redos_variants.swift: #-----| 2 -> [RegExpOpt] (?:,\d*)? #-----| 3 -> [RegExpConstant, RegExpNormalChar] } -# 287| [RegExpCaret] ^ +# 287| [RegExpCharacterClassEscape] \d -# 287| [RegExpSequence] ^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|\{\d+(?:,\d*)?}) -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpStar] (?:\s+|#.*|\(\?#[^)]*\))* -#-----| 2 -> [RegExpGroup] (?:[?*+]|\{\d+(?:,\d*)?}) +# 287| [RegExpPlus] \d+ +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 287| [RegExpGroup] (?:,\d*) +#-----| 0 -> [RegExpSequence] ,\d* + +# 287| [RegExpOpt] (?:,\d*)? +#-----| 0 -> [RegExpGroup] (?:,\d*) + +# 287| [RegExpConstant, RegExpNormalChar] , + +# 287| [RegExpSequence] ,\d* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] , +#-----| 1 -> [RegExpStar] \d* + +# 287| [RegExpCharacterClassEscape] \d + +# 287| [RegExpStar] \d* +#-----| 0 -> [RegExpCharacterClassEscape] \d # 287| [RegExpConstant, RegExpNormalChar] } -# 291| [RegExpConstant, RegExpNormalChar] - -# 291| [RegExpConstant, RegExpNormalChar] - -# 291| [RegExpOpt] ? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] - -# 291| [RegExpGroup] ((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+) -#-----| 0 -> [RegExpPlus] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+ - -# 291| [RegExpStar] ((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)* -#-----| 0 -> [RegExpGroup] ((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+) - -# 291| [RegExpGroup] ([ a-zA-Z{}]+) -#-----| 0 -> [RegExpPlus] [ a-zA-Z{}]+ - -# 291| [RegExpGroup] ([a-zA-Z]+) -#-----| 0 -> [RegExpPlus] [a-zA-Z]+ - -# 291| [RegExpGroup] ([a-zA-Z]+) -#-----| 0 -> [RegExpPlus] [a-zA-Z]+ - -# 291| [RegExpGroup] ([a-zA-Z]+) -#-----| 0 -> [RegExpPlus] [a-zA-Z]+ - -# 291| [RegExpGroup] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?) -#-----| 0 -> [RegExpSequence] \s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),? - -# 291| [RegExpPlus] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+ -#-----| 0 -> [RegExpGroup] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?) - -# 291| [RegExpConstant, RegExpNormalChar] , - -# 291| [RegExpOpt] ,? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] , - -# 291| [RegExpConstant, RegExpNormalChar] A - -# 291| [RegExpConstant, RegExpNormalChar] A - -# 291| [RegExpConstant, RegExpNormalChar] A - -# 291| [RegExpConstant, RegExpNormalChar] A - -# 291| [RegExpCharacterRange] A-Z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] A -#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z - -# 291| [RegExpCharacterRange] A-Z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] A -#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z - -# 291| [RegExpCharacterRange] A-Z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] A -#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z - -# 291| [RegExpCharacterRange] A-Z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] A -#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z - -# 291| [RegExpConstant, RegExpNormalChar] Z - -# 291| [RegExpConstant, RegExpNormalChar] Z - -# 291| [RegExpConstant, RegExpNormalChar] Z - -# 291| [RegExpConstant, RegExpNormalChar] Z - -# 291| [RegExpCharacterClass] [ a-zA-Z{}] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] -#-----| 1 -> [RegExpCharacterRange] a-z -#-----| 2 -> [RegExpCharacterRange] A-Z -#-----| 3 -> [RegExpConstant, RegExpNormalChar] { -#-----| 4 -> [RegExpConstant, RegExpNormalChar] } - -# 291| [RegExpPlus] [ a-zA-Z{}]+ -#-----| 0 -> [RegExpCharacterClass] [ a-zA-Z{}] - -# 291| [RegExpCharacterClass] [a-zA-Z] -#-----| 0 -> [RegExpCharacterRange] a-z -#-----| 1 -> [RegExpCharacterRange] A-Z - -# 291| [RegExpCharacterClass] [a-zA-Z] -#-----| 0 -> [RegExpCharacterRange] a-z -#-----| 1 -> [RegExpCharacterRange] A-Z - -# 291| [RegExpCharacterClass] [a-zA-Z] -#-----| 0 -> [RegExpCharacterRange] a-z -#-----| 1 -> [RegExpCharacterRange] A-Z - -# 291| [RegExpPlus] [a-zA-Z]+ -#-----| 0 -> [RegExpCharacterClass] [a-zA-Z] - -# 291| [RegExpPlus] [a-zA-Z]+ -#-----| 0 -> [RegExpCharacterClass] [a-zA-Z] - -# 291| [RegExpPlus] [a-zA-Z]+ -#-----| 0 -> [RegExpCharacterClass] [a-zA-Z] - -# 291| [RegExpConstant, RegExpEscape] \( - -# 291| [RegExpConstant, RegExpEscape] \) - -# 291| [RegExpConstant, RegExpEscape] \: - -# 291| [RegExpConstant, RegExpEscape] \[ - -# 291| [RegExpConstant, RegExpEscape] \] - -# 291| [RegExpCharacterClassEscape] \s - -# 291| [RegExpCharacterClassEscape] \s - -# 291| [RegExpCharacterClassEscape] \s - -# 291| [RegExpStar] \s* -#-----| 0 -> [RegExpCharacterClassEscape] \s - -# 291| [RegExpStar] \s* -#-----| 0 -> [RegExpCharacterClassEscape] \s - -# 291| [RegExpStar] \s* -#-----| 0 -> [RegExpCharacterClassEscape] \s - -# 291| [RegExpSequence] \s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),? -#-----| 0 -> [RegExpStar] \s* -#-----| 1 -> [RegExpGroup] ([a-zA-Z]+) -#-----| 2 -> [RegExpConstant, RegExpEscape] \: -#-----| 3 -> [RegExpOpt] ? -#-----| 4 -> [RegExpGroup] ([ a-zA-Z{}]+) -#-----| 5 -> [RegExpOpt] ,? - # 291| [RegExpConstant, RegExpEscape] \{ # 291| [RegExpSequence] \{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\} @@ -3158,13 +3026,22 @@ redos_variants.swift: #-----| 9 -> [RegExpConstant, RegExpEscape] \] #-----| 10 -> [RegExpConstant, RegExpEscape] \} -# 291| [RegExpConstant, RegExpEscape] \} +# 291| [RegExpConstant, RegExpEscape] \[ -# 291| [RegExpConstant, RegExpNormalChar] a +# 291| [RegExpCharacterClassEscape] \s -# 291| [RegExpConstant, RegExpNormalChar] a +# 291| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s -# 291| [RegExpConstant, RegExpNormalChar] a +# 291| [RegExpGroup] ([a-zA-Z]+) +#-----| 0 -> [RegExpPlus] [a-zA-Z]+ + +# 291| [RegExpCharacterClass] [a-zA-Z] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z + +# 291| [RegExpPlus] [a-zA-Z]+ +#-----| 0 -> [RegExpCharacterClass] [a-zA-Z] # 291| [RegExpConstant, RegExpNormalChar] a @@ -3172,13 +3049,29 @@ redos_variants.swift: #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpConstant, RegExpNormalChar] z -# 291| [RegExpCharacterRange] a-z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] z +# 291| [RegExpConstant, RegExpNormalChar] z -# 291| [RegExpCharacterRange] a-z -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] z +# 291| [RegExpConstant, RegExpNormalChar] A + +# 291| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpEscape] \( + +# 291| [RegExpGroup] ([a-zA-Z]+) +#-----| 0 -> [RegExpPlus] [a-zA-Z]+ + +# 291| [RegExpCharacterClass] [a-zA-Z] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z + +# 291| [RegExpPlus] [a-zA-Z]+ +#-----| 0 -> [RegExpCharacterClass] [a-zA-Z] + +# 291| [RegExpConstant, RegExpNormalChar] a # 291| [RegExpCharacterRange] a-z #-----| 0 -> [RegExpConstant, RegExpNormalChar] a @@ -3186,16 +3079,123 @@ redos_variants.swift: # 291| [RegExpConstant, RegExpNormalChar] z -# 291| [RegExpConstant, RegExpNormalChar] z +# 291| [RegExpConstant, RegExpNormalChar] A + +# 291| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpEscape] \) + +# 291| [RegExpGroup] ((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+) +#-----| 0 -> [RegExpPlus] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+ + +# 291| [RegExpStar] ((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)* +#-----| 0 -> [RegExpGroup] ((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+) + +# 291| [RegExpGroup] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?) +#-----| 0 -> [RegExpSequence] \s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),? + +# 291| [RegExpPlus] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+ +#-----| 0 -> [RegExpGroup] (\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?) + +# 291| [RegExpCharacterClassEscape] \s + +# 291| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 291| [RegExpSequence] \s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),? +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpGroup] ([a-zA-Z]+) +#-----| 2 -> [RegExpConstant, RegExpEscape] \: +#-----| 3 -> [RegExpOpt] ? +#-----| 4 -> [RegExpGroup] ([ a-zA-Z{}]+) +#-----| 5 -> [RegExpOpt] ,? + +# 291| [RegExpGroup] ([a-zA-Z]+) +#-----| 0 -> [RegExpPlus] [a-zA-Z]+ + +# 291| [RegExpCharacterClass] [a-zA-Z] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z + +# 291| [RegExpPlus] [a-zA-Z]+ +#-----| 0 -> [RegExpCharacterClass] [a-zA-Z] + +# 291| [RegExpConstant, RegExpNormalChar] a + +# 291| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z # 291| [RegExpConstant, RegExpNormalChar] z +# 291| [RegExpConstant, RegExpNormalChar] A + +# 291| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpEscape] \: + +# 291| [RegExpConstant, RegExpNormalChar] + +# 291| [RegExpOpt] ? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] + +# 291| [RegExpGroup] ([ a-zA-Z{}]+) +#-----| 0 -> [RegExpPlus] [ a-zA-Z{}]+ + +# 291| [RegExpCharacterClass] [ a-zA-Z{}] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] +#-----| 1 -> [RegExpCharacterRange] a-z +#-----| 2 -> [RegExpCharacterRange] A-Z +#-----| 3 -> [RegExpConstant, RegExpNormalChar] { +#-----| 4 -> [RegExpConstant, RegExpNormalChar] } + +# 291| [RegExpPlus] [ a-zA-Z{}]+ +#-----| 0 -> [RegExpCharacterClass] [ a-zA-Z{}] + +# 291| [RegExpConstant, RegExpNormalChar] + +# 291| [RegExpConstant, RegExpNormalChar] a + +# 291| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + # 291| [RegExpConstant, RegExpNormalChar] z +# 291| [RegExpConstant, RegExpNormalChar] A + +# 291| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 291| [RegExpConstant, RegExpNormalChar] Z + # 291| [RegExpConstant, RegExpNormalChar] { # 291| [RegExpConstant, RegExpNormalChar] } +# 291| [RegExpConstant, RegExpNormalChar] , + +# 291| [RegExpOpt] ,? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] , + +# 291| [RegExpCharacterClassEscape] \s + +# 291| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 291| [RegExpConstant, RegExpEscape] \] + +# 291| [RegExpConstant, RegExpEscape] \} + # 295| [RegExpGroup] (a+|b+|c+) #-----| 0 -> [RegExpAlt] a+|b+|c+ @@ -3223,11 +3223,11 @@ redos_variants.swift: # 295| [RegExpConstant, RegExpNormalChar] c -# 295| [RegExpConstant, RegExpNormalChar] c - # 295| [RegExpPlus] c+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] c +# 295| [RegExpConstant, RegExpNormalChar] c + # 299| [RegExpGroup] (((a+a?)*)+b+) #-----| 0 -> [RegExpSequence] ((a+a?)*)+b+ @@ -3249,8 +3249,6 @@ redos_variants.swift: # 299| [RegExpConstant, RegExpNormalChar] a -# 299| [RegExpConstant, RegExpNormalChar] a - # 299| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a @@ -3258,6 +3256,8 @@ redos_variants.swift: #-----| 0 -> [RegExpPlus] a+ #-----| 1 -> [RegExpOpt] a? +# 299| [RegExpConstant, RegExpNormalChar] a + # 299| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a @@ -3297,21 +3297,21 @@ redos_variants.swift: # 306| [RegExpConstant, RegExpNormalChar] a -# 306| [RegExpConstant, RegExpNormalChar] a +# 306| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 306| [RegExpConstant, RegExpNormalChar] aaaa # 306| [RegExpConstant, RegExpNormalChar] a # 306| [RegExpStar] a* #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 306| [RegExpPlus] a+ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +# 306| [RegExpConstant, RegExpNormalChar] a # 306| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 306| [RegExpConstant, RegExpNormalChar] aaaa - # 309| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ @@ -3326,23 +3326,21 @@ redos_variants.swift: # 309| [RegExpConstant, RegExpNormalChar] a -# 309| [RegExpConstant, RegExpNormalChar] a +# 309| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 309| [RegExpConstant, RegExpNormalChar] aaaa # 309| [RegExpConstant, RegExpNormalChar] a # 309| [RegExpStar] a* #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 309| [RegExpPlus] a+ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +# 309| [RegExpConstant, RegExpNormalChar] a # 309| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 309| [RegExpConstant, RegExpNormalChar] aaaa - -# 313| [RegExpDollar] $ - # 313| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ @@ -3361,6 +3359,8 @@ redos_variants.swift: # 313| [RegExpConstant, RegExpNormalChar] aaaaa +# 313| [RegExpDollar] $ + # 316| [RegExpGroup] (\n+) #-----| 0 -> [RegExpPlus] \n+ @@ -3374,13 +3374,13 @@ redos_variants.swift: # 316| [RegExpConstant, RegExpEscape] \n -# 316| [RegExpConstant, RegExpEscape] \n - -# 316| [RegExpConstant, RegExpEscape] \n - # 316| [RegExpPlus] \n+ #-----| 0 -> [RegExpConstant, RegExpEscape] \n +# 316| [RegExpConstant, RegExpEscape] \n + +# 316| [RegExpConstant, RegExpEscape] \n + # 319| [RegExpGroup] (\n+) #-----| 0 -> [RegExpPlus] \n+ @@ -3394,14 +3394,12 @@ redos_variants.swift: # 319| [RegExpConstant, RegExpEscape] \n -# 319| [RegExpConstant, RegExpEscape] \n - -# 319| [RegExpConstant, RegExpEscape] \n - # 319| [RegExpPlus] \n+ #-----| 0 -> [RegExpConstant, RegExpEscape] \n -# 323| [RegExpDollar] $ +# 319| [RegExpConstant, RegExpEscape] \n + +# 319| [RegExpConstant, RegExpEscape] \n # 323| [RegExpGroup] (\n+) #-----| 0 -> [RegExpPlus] \n+ @@ -3417,14 +3415,14 @@ redos_variants.swift: # 323| [RegExpConstant, RegExpEscape] \n -# 323| [RegExpConstant, RegExpEscape] \n - -# 323| [RegExpConstant, RegExpEscape] \n - # 323| [RegExpPlus] \n+ #-----| 0 -> [RegExpConstant, RegExpEscape] \n -# 327| [RegExpDollar] $ +# 323| [RegExpConstant, RegExpEscape] \n + +# 323| [RegExpConstant, RegExpEscape] \n + +# 323| [RegExpDollar] $ # 327| [RegExpGroup] ([^X]+) #-----| 0 -> [RegExpPlus] [^X]+ @@ -3436,15 +3434,15 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] ([^X]+)* #-----| 1 -> [RegExpDollar] $ -# 327| [RegExpConstant, RegExpNormalChar] X - # 327| [RegExpCharacterClass] [^X] #-----| 0 -> [RegExpConstant, RegExpNormalChar] X # 327| [RegExpPlus] [^X]+ #-----| 0 -> [RegExpCharacterClass] [^X] -# 331| [RegExpDollar] $ +# 327| [RegExpConstant, RegExpNormalChar] X + +# 327| [RegExpDollar] $ # 331| [RegExpGroup] (([^X]b)+) #-----| 0 -> [RegExpPlus] ([^X]b)+ @@ -3462,8 +3460,6 @@ redos_variants.swift: # 331| [RegExpPlus] ([^X]b)+ #-----| 0 -> [RegExpGroup] ([^X]b) -# 331| [RegExpConstant, RegExpNormalChar] X - # 331| [RegExpCharacterClass] [^X] #-----| 0 -> [RegExpConstant, RegExpNormalChar] X @@ -3471,16 +3467,11 @@ redos_variants.swift: #-----| 0 -> [RegExpCharacterClass] [^X] #-----| 1 -> [RegExpConstant, RegExpNormalChar] b +# 331| [RegExpConstant, RegExpNormalChar] X + # 331| [RegExpConstant, RegExpNormalChar] b -# 334| [RegExpDollar] $ - -# 334| [RegExpAlt] $|[^X]b -#-----| 0 -> [RegExpDollar] $ -#-----| 1 -> [RegExpSequence] [^X]b - -# 334| [RegExpGroup] ($|[^X]b) -#-----| 0 -> [RegExpAlt] $|[^X]b +# 331| [RegExpDollar] $ # 334| [RegExpGroup] (([^X]b)+) #-----| 0 -> [RegExpPlus] ([^X]b)+ @@ -3498,13 +3489,6 @@ redos_variants.swift: # 334| [RegExpPlus] ([^X]b)+ #-----| 0 -> [RegExpGroup] ([^X]b) -# 334| [RegExpConstant, RegExpNormalChar] X - -# 334| [RegExpConstant, RegExpNormalChar] X - -# 334| [RegExpCharacterClass] [^X] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] X - # 334| [RegExpCharacterClass] [^X] #-----| 0 -> [RegExpConstant, RegExpNormalChar] X @@ -3512,22 +3496,29 @@ redos_variants.swift: #-----| 0 -> [RegExpCharacterClass] [^X] #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 334| [RegExpSequence] [^X]b -#-----| 0 -> [RegExpCharacterClass] [^X] -#-----| 1 -> [RegExpConstant, RegExpNormalChar] b +# 334| [RegExpConstant, RegExpNormalChar] X # 334| [RegExpConstant, RegExpNormalChar] b -# 334| [RegExpConstant, RegExpNormalChar] b +# 334| [RegExpGroup] ($|[^X]b) +#-----| 0 -> [RegExpAlt] $|[^X]b -# 337| [RegExpDollar] $ +# 334| [RegExpDollar] $ -# 337| [RegExpAlt] $|[^X]b +# 334| [RegExpAlt] $|[^X]b #-----| 0 -> [RegExpDollar] $ #-----| 1 -> [RegExpSequence] [^X]b -# 337| [RegExpGroup] ($|[^X]b) -#-----| 0 -> [RegExpAlt] $|[^X]b +# 334| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + +# 334| [RegExpSequence] [^X]b +#-----| 0 -> [RegExpCharacterClass] [^X] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 334| [RegExpConstant, RegExpNormalChar] X + +# 334| [RegExpConstant, RegExpNormalChar] b # 337| [RegExpGroup] (([^X]b)+) #-----| 0 -> [RegExpPlus] ([^X]b)+ @@ -3545,13 +3536,6 @@ redos_variants.swift: # 337| [RegExpPlus] ([^X]b)+ #-----| 0 -> [RegExpGroup] ([^X]b) -# 337| [RegExpConstant, RegExpNormalChar] X - -# 337| [RegExpConstant, RegExpNormalChar] X - -# 337| [RegExpCharacterClass] [^X] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] X - # 337| [RegExpCharacterClass] [^X] #-----| 0 -> [RegExpConstant, RegExpNormalChar] X @@ -3559,22 +3543,29 @@ redos_variants.swift: #-----| 0 -> [RegExpCharacterClass] [^X] #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 337| [RegExpSequence] [^X]b -#-----| 0 -> [RegExpCharacterClass] [^X] -#-----| 1 -> [RegExpConstant, RegExpNormalChar] b +# 337| [RegExpConstant, RegExpNormalChar] X # 337| [RegExpConstant, RegExpNormalChar] b -# 337| [RegExpConstant, RegExpNormalChar] b +# 337| [RegExpGroup] ($|[^X]b) +#-----| 0 -> [RegExpAlt] $|[^X]b -# 341| [RegExpDollar] $ +# 337| [RegExpDollar] $ -# 341| [RegExpAlt] $|[^X]c +# 337| [RegExpAlt] $|[^X]b #-----| 0 -> [RegExpDollar] $ -#-----| 1 -> [RegExpSequence] [^X]c +#-----| 1 -> [RegExpSequence] [^X]b -# 341| [RegExpGroup] ($|[^X]c) -#-----| 0 -> [RegExpAlt] $|[^X]c +# 337| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + +# 337| [RegExpSequence] [^X]b +#-----| 0 -> [RegExpCharacterClass] [^X] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 337| [RegExpConstant, RegExpNormalChar] X + +# 337| [RegExpConstant, RegExpNormalChar] b # 341| [RegExpGroup] (([^X]b)+) #-----| 0 -> [RegExpPlus] ([^X]b)+ @@ -3592,13 +3583,6 @@ redos_variants.swift: # 341| [RegExpPlus] ([^X]b)+ #-----| 0 -> [RegExpGroup] ([^X]b) -# 341| [RegExpConstant, RegExpNormalChar] X - -# 341| [RegExpConstant, RegExpNormalChar] X - -# 341| [RegExpCharacterClass] [^X] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] X - # 341| [RegExpCharacterClass] [^X] #-----| 0 -> [RegExpConstant, RegExpNormalChar] X @@ -3606,11 +3590,27 @@ redos_variants.swift: #-----| 0 -> [RegExpCharacterClass] [^X] #-----| 1 -> [RegExpConstant, RegExpNormalChar] b +# 341| [RegExpConstant, RegExpNormalChar] X + +# 341| [RegExpConstant, RegExpNormalChar] b + +# 341| [RegExpGroup] ($|[^X]c) +#-----| 0 -> [RegExpAlt] $|[^X]c + +# 341| [RegExpDollar] $ + +# 341| [RegExpAlt] $|[^X]c +#-----| 0 -> [RegExpDollar] $ +#-----| 1 -> [RegExpSequence] [^X]c + +# 341| [RegExpCharacterClass] [^X] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] X + # 341| [RegExpSequence] [^X]c #-----| 0 -> [RegExpCharacterClass] [^X] #-----| 1 -> [RegExpConstant, RegExpNormalChar] c -# 341| [RegExpConstant, RegExpNormalChar] b +# 341| [RegExpConstant, RegExpNormalChar] X # 341| [RegExpConstant, RegExpNormalChar] c @@ -3669,8 +3669,12 @@ redos_variants.swift: # 350| [RegExpGroup] (ab) #-----| 0 -> [RegExpConstant, RegExpNormalChar] ab -# 350| [RegExpGroup] (ab) -#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab +# 350| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 350| [RegExpConstant, RegExpNormalChar] ab + +# 350| [RegExpConstant, RegExpNormalChar] abab # 350| [RegExpGroup] (ab) #-----| 0 -> [RegExpConstant, RegExpNormalChar] ab @@ -3678,20 +3682,16 @@ redos_variants.swift: # 350| [RegExpStar] (ab)* #-----| 0 -> [RegExpGroup] (ab) -# 350| [RegExpPlus] (ab)+ -#-----| 0 -> [RegExpGroup] (ab) +# 350| [RegExpConstant, RegExpNormalChar] ab + +# 350| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab # 350| [RegExpPlus] (ab)+ #-----| 0 -> [RegExpGroup] (ab) # 350| [RegExpConstant, RegExpNormalChar] ab -# 350| [RegExpConstant, RegExpNormalChar] ab - -# 350| [RegExpConstant, RegExpNormalChar] ab - -# 350| [RegExpConstant, RegExpNormalChar] abab - # 353| [RegExpGroup] ((ab)+) #-----| 0 -> [RegExpPlus] (ab)+ @@ -3707,8 +3707,12 @@ redos_variants.swift: # 353| [RegExpGroup] (ab) #-----| 0 -> [RegExpConstant, RegExpNormalChar] ab -# 353| [RegExpGroup] (ab) -#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab +# 353| [RegExpPlus] (ab)+ +#-----| 0 -> [RegExpGroup] (ab) + +# 353| [RegExpConstant, RegExpNormalChar] ab + +# 353| [RegExpConstant, RegExpNormalChar] abab # 353| [RegExpGroup] (ab) #-----| 0 -> [RegExpConstant, RegExpNormalChar] ab @@ -3716,20 +3720,16 @@ redos_variants.swift: # 353| [RegExpStar] (ab)* #-----| 0 -> [RegExpGroup] (ab) -# 353| [RegExpPlus] (ab)+ -#-----| 0 -> [RegExpGroup] (ab) +# 353| [RegExpConstant, RegExpNormalChar] ab + +# 353| [RegExpGroup] (ab) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ab # 353| [RegExpPlus] (ab)+ #-----| 0 -> [RegExpGroup] (ab) # 353| [RegExpConstant, RegExpNormalChar] ab -# 353| [RegExpConstant, RegExpNormalChar] ab - -# 353| [RegExpConstant, RegExpNormalChar] ab - -# 353| [RegExpConstant, RegExpNormalChar] abab - # 356| [RegExpGroup] ((ab)+) #-----| 0 -> [RegExpPlus] (ab)+ @@ -3758,8 +3758,6 @@ redos_variants.swift: # 359| [RegExpConstant, RegExpNormalChar] ab -# 363| [RegExpDollar] $ - # 363| [RegExpGroup] ((ab)+) #-----| 0 -> [RegExpPlus] (ab)+ @@ -3778,6 +3776,8 @@ redos_variants.swift: # 363| [RegExpConstant, RegExpNormalChar] ab +# 363| [RegExpDollar] $ + # 366| [RegExpGroup] ((ab)+) #-----| 0 -> [RegExpPlus] (ab)+ @@ -3799,55 +3799,55 @@ redos_variants.swift: # 366| [RegExpPlus] (ab)+ #-----| 0 -> [RegExpGroup] (ab) -# 366| [RegExpConstant, RegExpNormalChar] 1 - -# 366| [RegExpConstant, RegExpNormalChar] 1 - -# 366| [RegExpConstant, RegExpNormalChar] 2 - -# 366| [RegExpConstant, RegExpNormalChar] 2 - -# 366| [RegExpConstant, RegExpNormalChar] 3 - -# 366| [RegExpConstant, RegExpNormalChar] 3 +# 366| [RegExpConstant, RegExpNormalChar] ab # 366| [RegExpCharacterClass] [a1] #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 366| [RegExpCharacterClass] [a2] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 +# 366| [RegExpConstant, RegExpNormalChar] a -# 366| [RegExpCharacterClass] [a3] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 3 +# 366| [RegExpConstant, RegExpNormalChar] 1 # 366| [RegExpCharacterClass] [b1] #-----| 0 -> [RegExpConstant, RegExpNormalChar] b #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 +# 366| [RegExpConstant, RegExpNormalChar] b + +# 366| [RegExpConstant, RegExpNormalChar] 1 + +# 366| [RegExpCharacterClass] [a2] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 + +# 366| [RegExpConstant, RegExpNormalChar] a + +# 366| [RegExpConstant, RegExpNormalChar] 2 + # 366| [RegExpCharacterClass] [b2] #-----| 0 -> [RegExpConstant, RegExpNormalChar] b #-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 +# 366| [RegExpConstant, RegExpNormalChar] b + +# 366| [RegExpConstant, RegExpNormalChar] 2 + +# 366| [RegExpCharacterClass] [a3] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 3 + +# 366| [RegExpConstant, RegExpNormalChar] a + +# 366| [RegExpConstant, RegExpNormalChar] 3 + # 366| [RegExpCharacterClass] [b3] #-----| 0 -> [RegExpConstant, RegExpNormalChar] b #-----| 1 -> [RegExpConstant, RegExpNormalChar] 3 -# 366| [RegExpConstant, RegExpNormalChar] a - -# 366| [RegExpConstant, RegExpNormalChar] a - -# 366| [RegExpConstant, RegExpNormalChar] a - -# 366| [RegExpConstant, RegExpNormalChar] ab - # 366| [RegExpConstant, RegExpNormalChar] b -# 366| [RegExpConstant, RegExpNormalChar] b - -# 366| [RegExpConstant, RegExpNormalChar] b +# 366| [RegExpConstant, RegExpNormalChar] 3 # 369| [RegExpGroup] ((ab)+) #-----| 0 -> [RegExpPlus] (ab)+ @@ -3870,58 +3870,55 @@ redos_variants.swift: # 369| [RegExpPlus] (ab)+ #-----| 0 -> [RegExpGroup] (ab) -# 369| [RegExpConstant, RegExpNormalChar] 1 - -# 369| [RegExpConstant, RegExpNormalChar] 1 - -# 369| [RegExpConstant, RegExpNormalChar] 2 - -# 369| [RegExpConstant, RegExpNormalChar] 2 - -# 369| [RegExpConstant, RegExpNormalChar] 3 - -# 369| [RegExpConstant, RegExpNormalChar] 3 +# 369| [RegExpConstant, RegExpNormalChar] ab # 369| [RegExpCharacterClass] [a1] #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 369| [RegExpCharacterClass] [a2] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 +# 369| [RegExpConstant, RegExpNormalChar] a -# 369| [RegExpCharacterClass] [a3] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 3 +# 369| [RegExpConstant, RegExpNormalChar] 1 # 369| [RegExpCharacterClass] [b1] #-----| 0 -> [RegExpConstant, RegExpNormalChar] b #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 +# 369| [RegExpConstant, RegExpNormalChar] b + +# 369| [RegExpConstant, RegExpNormalChar] 1 + +# 369| [RegExpCharacterClass] [a2] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 + +# 369| [RegExpConstant, RegExpNormalChar] a + +# 369| [RegExpConstant, RegExpNormalChar] 2 + # 369| [RegExpCharacterClass] [b2] #-----| 0 -> [RegExpConstant, RegExpNormalChar] b #-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 +# 369| [RegExpConstant, RegExpNormalChar] b + +# 369| [RegExpConstant, RegExpNormalChar] 2 + +# 369| [RegExpCharacterClass] [a3] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 3 + +# 369| [RegExpConstant, RegExpNormalChar] a + +# 369| [RegExpConstant, RegExpNormalChar] 3 + # 369| [RegExpCharacterClass] [b3] #-----| 0 -> [RegExpConstant, RegExpNormalChar] b #-----| 1 -> [RegExpConstant, RegExpNormalChar] 3 -# 369| [RegExpConstant, RegExpNormalChar] a - -# 369| [RegExpConstant, RegExpNormalChar] a - -# 369| [RegExpConstant, RegExpNormalChar] a - -# 369| [RegExpConstant, RegExpNormalChar] ab - # 369| [RegExpConstant, RegExpNormalChar] b -# 369| [RegExpConstant, RegExpNormalChar] b - -# 369| [RegExpConstant, RegExpNormalChar] b - -# 373| [RegExpGroup] (.) -#-----| 0 -> [RegExpDot] . +# 369| [RegExpConstant, RegExpNormalChar] 3 # 373| [RegExpGroup] ([\n\s]+) #-----| 0 -> [RegExpPlus] [\n\s]+ @@ -3933,8 +3930,6 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] ([\n\s]+)* #-----| 1 -> [RegExpGroup] (.) -# 373| [RegExpDot] . - # 373| [RegExpCharacterClass] [\n\s] #-----| 0 -> [RegExpConstant, RegExpEscape] \n #-----| 1 -> [RegExpCharacterClassEscape] \s @@ -3946,6 +3941,11 @@ redos_variants.swift: # 373| [RegExpCharacterClassEscape] \s +# 373| [RegExpGroup] (.) +#-----| 0 -> [RegExpDot] . + +# 373| [RegExpDot] . + # 376| [RegExpGroup] (A*A*X) #-----| 0 -> [RegExpSequence] A*A*X @@ -3954,11 +3954,6 @@ redos_variants.swift: # 376| [RegExpConstant, RegExpNormalChar] A -# 376| [RegExpConstant, RegExpNormalChar] A - -# 376| [RegExpStar] A* -#-----| 0 -> [RegExpConstant, RegExpNormalChar] A - # 376| [RegExpStar] A* #-----| 0 -> [RegExpConstant, RegExpNormalChar] A @@ -3967,6 +3962,11 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] A* #-----| 2 -> [RegExpConstant, RegExpNormalChar] X +# 376| [RegExpConstant, RegExpNormalChar] A + +# 376| [RegExpStar] A* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A + # 376| [RegExpConstant, RegExpNormalChar] X # 379| [RegExpGroup] ([^\\\]]+) @@ -3986,14 +3986,6 @@ redos_variants.swift: # 379| [RegExpConstant, RegExpEscape] \] -# 392| [RegExpGroup] (b+) -#-----| 0 -> [RegExpPlus] b+ - -# 392| [RegExpPlus] (b+)+ -#-----| 0 -> [RegExpGroup] (b+) - -# 392| [RegExpConstant, RegExpNormalChar] X - # 392| [RegExpConstant, RegExpNormalChar] a # 392| [RegExpRange] a{2,3} @@ -4004,142 +3996,18 @@ redos_variants.swift: #-----| 1 -> [RegExpPlus] (b+)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] X +# 392| [RegExpGroup] (b+) +#-----| 0 -> [RegExpPlus] b+ + +# 392| [RegExpPlus] (b+)+ +#-----| 0 -> [RegExpGroup] (b+) + # 392| [RegExpConstant, RegExpNormalChar] b # 392| [RegExpPlus] b+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] b -# 396| [RegExpConstant, RegExpNormalChar] " - -# 396| [RegExpConstant, RegExpNormalChar] " - -# 396| [RegExpConstant, RegExpNormalChar] " - -# 396| [RegExpSequence] "[^"]*" -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " -#-----| 1 -> [RegExpStar] [^"]* -#-----| 2 -> [RegExpConstant, RegExpNormalChar] " - -# 396| [RegExpConstant, RegExpNormalChar] ' - -# 396| [RegExpConstant, RegExpNormalChar] ' - -# 396| [RegExpConstant, RegExpNormalChar] ' - -# 396| [RegExpSequence] '[^']*' -#-----| 0 -> [RegExpConstant, RegExpNormalChar] ' -#-----| 1 -> [RegExpStar] [^']* -#-----| 2 -> [RegExpConstant, RegExpNormalChar] ' - -# 396| [RegExpGroup] ((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*) -#-----| 0 -> [RegExpStar] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)* - -# 396| [RegExpGroup] (?:"[^"]*") -#-----| 0 -> [RegExpSequence] "[^"]*" - -# 396| [RegExpAlt] (?:"[^"]*")|(?:'[^']*')|[^>\s]+ -#-----| 0 -> [RegExpGroup] (?:"[^"]*") -#-----| 1 -> [RegExpGroup] (?:'[^']*') -#-----| 2 -> [RegExpPlus] [^>\s]+ - -# 396| [RegExpGroup] (?:'[^']*') -#-----| 0 -> [RegExpSequence] '[^']*' - -# 396| [RegExpGroup] (?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) -#-----| 0 -> [RegExpAlt] (?:"[^"]*")|(?:'[^']*')|[^>\s]+ - -# 396| [RegExpGroup] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+)) -#-----| 0 -> [RegExpSequence] \s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) - -# 396| [RegExpOpt] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? -#-----| 0 -> [RegExpGroup] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+)) - -# 396| [RegExpGroup] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?) -#-----| 0 -> [RegExpSequence] \s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? - -# 396| [RegExpStar] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)* -#-----| 0 -> [RegExpGroup] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?) - -# 396| [RegExpGroup] (\/?) -#-----| 0 -> [RegExpOpt] \/? - -# 396| [RegExpGroup] (\w+) -#-----| 0 -> [RegExpPlus] \w+ - -# 396| [RegExpConstant, RegExpNormalChar] < - -# 396| [RegExpConstant, RegExpNormalChar] = - -# 396| [RegExpConstant, RegExpNormalChar] > - -# 396| [RegExpConstant, RegExpNormalChar] > - -# 396| [RegExpCharacterClass] [^"] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " - -# 396| [RegExpStar] [^"]* -#-----| 0 -> [RegExpCharacterClass] [^"] - -# 396| [RegExpCharacterClass] [^'] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] ' - -# 396| [RegExpStar] [^']* -#-----| 0 -> [RegExpCharacterClass] [^'] - -# 396| [RegExpCharacterClass] [^>\s] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] > -#-----| 1 -> [RegExpCharacterClassEscape] \s - -# 396| [RegExpPlus] [^>\s]+ -#-----| 0 -> [RegExpCharacterClass] [^>\s] - -# 396| [RegExpConstant, RegExpEscape] \/ - -# 396| [RegExpOpt] \/? -#-----| 0 -> [RegExpConstant, RegExpEscape] \/ - -# 396| [RegExpCharacterClassEscape] \s - -# 396| [RegExpCharacterClassEscape] \s - -# 396| [RegExpCharacterClassEscape] \s - -# 396| [RegExpCharacterClassEscape] \s - -# 396| [RegExpCharacterClassEscape] \s - -# 396| [RegExpStar] \s* -#-----| 0 -> [RegExpCharacterClassEscape] \s - -# 396| [RegExpStar] \s* -#-----| 0 -> [RegExpCharacterClassEscape] \s - -# 396| [RegExpStar] \s* -#-----| 0 -> [RegExpCharacterClassEscape] \s - -# 396| [RegExpSequence] \s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) -#-----| 0 -> [RegExpStar] \s* -#-----| 1 -> [RegExpConstant, RegExpNormalChar] = -#-----| 2 -> [RegExpStar] \s* -#-----| 3 -> [RegExpGroup] (?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) - -# 396| [RegExpPlus] \s+ -#-----| 0 -> [RegExpCharacterClassEscape] \s - -# 396| [RegExpSequence] \s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? -#-----| 0 -> [RegExpPlus] \s+ -#-----| 1 -> [RegExpPlus] \w+ -#-----| 2 -> [RegExpOpt] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? - -# 396| [RegExpCharacterClassEscape] \w - -# 396| [RegExpCharacterClassEscape] \w - -# 396| [RegExpPlus] \w+ -#-----| 0 -> [RegExpCharacterClassEscape] \w - -# 396| [RegExpPlus] \w+ -#-----| 0 -> [RegExpCharacterClassEscape] \w +# 392| [RegExpConstant, RegExpNormalChar] X # 396| [RegExpCaret] ^ @@ -4152,6 +4020,138 @@ redos_variants.swift: #-----| 5 -> [RegExpGroup] (\/?) #-----| 6 -> [RegExpConstant, RegExpNormalChar] > +# 396| [RegExpConstant, RegExpNormalChar] < + +# 396| [RegExpGroup] (\w+) +#-----| 0 -> [RegExpPlus] \w+ + +# 396| [RegExpCharacterClassEscape] \w + +# 396| [RegExpPlus] \w+ +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 396| [RegExpGroup] ((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*) +#-----| 0 -> [RegExpStar] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)* + +# 396| [RegExpGroup] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?) +#-----| 0 -> [RegExpSequence] \s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? + +# 396| [RegExpStar] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)* +#-----| 0 -> [RegExpGroup] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?) + +# 396| [RegExpCharacterClassEscape] \s + +# 396| [RegExpPlus] \s+ +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 396| [RegExpSequence] \s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? +#-----| 0 -> [RegExpPlus] \s+ +#-----| 1 -> [RegExpPlus] \w+ +#-----| 2 -> [RegExpOpt] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? + +# 396| [RegExpCharacterClassEscape] \w + +# 396| [RegExpPlus] \w+ +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 396| [RegExpGroup] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+)) +#-----| 0 -> [RegExpSequence] \s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) + +# 396| [RegExpOpt] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? +#-----| 0 -> [RegExpGroup] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+)) + +# 396| [RegExpCharacterClassEscape] \s + +# 396| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 396| [RegExpSequence] \s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] = +#-----| 2 -> [RegExpStar] \s* +#-----| 3 -> [RegExpGroup] (?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) + +# 396| [RegExpConstant, RegExpNormalChar] = + +# 396| [RegExpCharacterClassEscape] \s + +# 396| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 396| [RegExpGroup] (?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) +#-----| 0 -> [RegExpAlt] (?:"[^"]*")|(?:'[^']*')|[^>\s]+ + +# 396| [RegExpGroup] (?:"[^"]*") +#-----| 0 -> [RegExpSequence] "[^"]*" + +# 396| [RegExpAlt] (?:"[^"]*")|(?:'[^']*')|[^>\s]+ +#-----| 0 -> [RegExpGroup] (?:"[^"]*") +#-----| 1 -> [RegExpGroup] (?:'[^']*') +#-----| 2 -> [RegExpPlus] [^>\s]+ + +# 396| [RegExpConstant, RegExpNormalChar] " + +# 396| [RegExpSequence] "[^"]*" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpStar] [^"]* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 396| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " + +# 396| [RegExpStar] [^"]* +#-----| 0 -> [RegExpCharacterClass] [^"] + +# 396| [RegExpConstant, RegExpNormalChar] " + +# 396| [RegExpConstant, RegExpNormalChar] " + +# 396| [RegExpGroup] (?:'[^']*') +#-----| 0 -> [RegExpSequence] '[^']*' + +# 396| [RegExpConstant, RegExpNormalChar] ' + +# 396| [RegExpSequence] '[^']*' +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ' +#-----| 1 -> [RegExpStar] [^']* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] ' + +# 396| [RegExpCharacterClass] [^'] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ' + +# 396| [RegExpStar] [^']* +#-----| 0 -> [RegExpCharacterClass] [^'] + +# 396| [RegExpConstant, RegExpNormalChar] ' + +# 396| [RegExpConstant, RegExpNormalChar] ' + +# 396| [RegExpCharacterClass] [^>\s] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] > +#-----| 1 -> [RegExpCharacterClassEscape] \s + +# 396| [RegExpPlus] [^>\s]+ +#-----| 0 -> [RegExpCharacterClass] [^>\s] + +# 396| [RegExpConstant, RegExpNormalChar] > + +# 396| [RegExpCharacterClassEscape] \s + +# 396| [RegExpCharacterClassEscape] \s + +# 396| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 396| [RegExpGroup] (\/?) +#-----| 0 -> [RegExpOpt] \/? + +# 396| [RegExpConstant, RegExpEscape] \/ + +# 396| [RegExpOpt] \/? +#-----| 0 -> [RegExpConstant, RegExpEscape] \/ + +# 396| [RegExpConstant, RegExpNormalChar] > + # 399| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ @@ -4164,14 +4164,27 @@ redos_variants.swift: #-----| 2 -> [RegExpCharacterClass] [\s\S] #-----| 3 -> [RegExpOpt] [\s\S]? -# 399| [RegExpCharacterClass] [\s\S] -#-----| 0 -> [RegExpCharacterClassEscape] \s -#-----| 1 -> [RegExpCharacterClassEscape] \S +# 399| [RegExpConstant, RegExpNormalChar] a + +# 399| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a # 399| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S +# 399| [RegExpCharacterClassEscape] \s + +# 399| [RegExpCharacterClassEscape] \S + +# 399| [RegExpCharacterClass] [\s\S] +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 399| [RegExpCharacterClassEscape] \s + +# 399| [RegExpCharacterClassEscape] \S + # 399| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S @@ -4179,22 +4192,9 @@ redos_variants.swift: # 399| [RegExpOpt] [\s\S]? #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 399| [RegExpCharacterClassEscape] \S - -# 399| [RegExpCharacterClassEscape] \S - -# 399| [RegExpCharacterClassEscape] \S - # 399| [RegExpCharacterClassEscape] \s -# 399| [RegExpCharacterClassEscape] \s - -# 399| [RegExpCharacterClassEscape] \s - -# 399| [RegExpConstant, RegExpNormalChar] a - -# 399| [RegExpPlus] a+ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +# 399| [RegExpCharacterClassEscape] \S # 402| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ @@ -4206,6 +4206,11 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] (a+)* #-----| 1 -> [RegExpRange] [\s\S]{2,3} +# 402| [RegExpConstant, RegExpNormalChar] a + +# 402| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + # 402| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S @@ -4213,19 +4218,9 @@ redos_variants.swift: # 402| [RegExpRange] [\s\S]{2,3} #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 402| [RegExpCharacterClassEscape] \S - # 402| [RegExpCharacterClassEscape] \s -# 402| [RegExpConstant, RegExpNormalChar] a - -# 402| [RegExpPlus] a+ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a - -# 405| [RegExpDollar] $ - -# 405| [RegExpGroup] ([\s\S]{2,}|X) -#-----| 0 -> [RegExpAlt] [\s\S]{2,}|X +# 402| [RegExpCharacterClassEscape] \S # 405| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ @@ -4238,7 +4233,13 @@ redos_variants.swift: #-----| 1 -> [RegExpGroup] ([\s\S]{2,}|X) #-----| 2 -> [RegExpDollar] $ -# 405| [RegExpConstant, RegExpNormalChar] X +# 405| [RegExpConstant, RegExpNormalChar] a + +# 405| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 405| [RegExpGroup] ([\s\S]{2,}|X) +#-----| 0 -> [RegExpAlt] [\s\S]{2,}|X # 405| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s @@ -4251,19 +4252,13 @@ redos_variants.swift: #-----| 0 -> [InfiniteRepetitionQuantifier, RegExpRange] [\s\S]{2,} #-----| 1 -> [RegExpConstant, RegExpNormalChar] X -# 405| [RegExpCharacterClassEscape] \S - # 405| [RegExpCharacterClassEscape] \s -# 405| [RegExpConstant, RegExpNormalChar] a +# 405| [RegExpCharacterClassEscape] \S -# 405| [RegExpPlus] a+ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +# 405| [RegExpConstant, RegExpNormalChar] X -# 408| [RegExpDollar] $ - -# 408| [RegExpGroup] ([\s\S]*|X) -#-----| 0 -> [RegExpAlt] [\s\S]*|X +# 405| [RegExpDollar] $ # 408| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ @@ -4276,7 +4271,13 @@ redos_variants.swift: #-----| 1 -> [RegExpGroup] ([\s\S]*|X) #-----| 2 -> [RegExpDollar] $ -# 408| [RegExpConstant, RegExpNormalChar] X +# 408| [RegExpConstant, RegExpNormalChar] a + +# 408| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 408| [RegExpGroup] ([\s\S]*|X) +#-----| 0 -> [RegExpAlt] [\s\S]*|X # 408| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s @@ -4289,16 +4290,13 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] [\s\S]* #-----| 1 -> [RegExpConstant, RegExpNormalChar] X -# 408| [RegExpCharacterClassEscape] \S - # 408| [RegExpCharacterClassEscape] \s -# 408| [RegExpConstant, RegExpNormalChar] a +# 408| [RegExpCharacterClassEscape] \S -# 408| [RegExpPlus] a+ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +# 408| [RegExpConstant, RegExpNormalChar] X -# 412| [RegExpDollar] $ +# 408| [RegExpDollar] $ # 412| [RegExpGroup] ((a+)*$|[\s\S]+) #-----| 0 -> [RegExpAlt] (a+)*$|[\s\S]+ @@ -4317,6 +4315,13 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] (a+)*$ #-----| 1 -> [RegExpPlus] [\s\S]+ +# 412| [RegExpConstant, RegExpNormalChar] a + +# 412| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 412| [RegExpDollar] $ + # 412| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S @@ -4324,30 +4329,13 @@ redos_variants.swift: # 412| [RegExpPlus] [\s\S]+ #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 412| [RegExpCharacterClassEscape] \S - # 412| [RegExpCharacterClassEscape] \s -# 412| [RegExpConstant, RegExpNormalChar] a - -# 412| [RegExpPlus] a+ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a - -# 415| [RegExpDollar] $ +# 412| [RegExpCharacterClassEscape] \S # 415| [RegExpGroup] ([\s\S]+|(a+)*$) #-----| 0 -> [RegExpAlt] [\s\S]+|(a+)*$ -# 415| [RegExpGroup] (a+) -#-----| 0 -> [RegExpPlus] a+ - -# 415| [RegExpStar] (a+)* -#-----| 0 -> [RegExpGroup] (a+) - -# 415| [RegExpSequence] (a+)*$ -#-----| 0 -> [RegExpStar] (a+)* -#-----| 1 -> [RegExpDollar] $ - # 415| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S @@ -4359,16 +4347,26 @@ redos_variants.swift: #-----| 0 -> [RegExpPlus] [\s\S]+ #-----| 1 -> [RegExpSequence] (a+)*$ +# 415| [RegExpCharacterClassEscape] \s + # 415| [RegExpCharacterClassEscape] \S -# 415| [RegExpCharacterClassEscape] \s +# 415| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 415| [RegExpStar] (a+)* +#-----| 0 -> [RegExpGroup] (a+) + +# 415| [RegExpSequence] (a+)*$ +#-----| 0 -> [RegExpStar] (a+)* +#-----| 1 -> [RegExpDollar] $ # 415| [RegExpConstant, RegExpNormalChar] a # 415| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 418| [RegExpDollar] $ +# 415| [RegExpDollar] $ # 418| [RegExpGroup] ((;|^)a+) #-----| 0 -> [RegExpSequence] (;|^)a+ @@ -4400,47 +4398,7 @@ redos_variants.swift: # 418| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 - -# 422| [RegExpGroup] (0|1) -#-----| 0 -> [RegExpAlt] 0|1 +# 418| [RegExpDollar] $ # 422| [RegExpGroup] (^|;) #-----| 0 -> [RegExpAlt] ^|; @@ -4464,132 +4422,174 @@ redos_variants.swift: #-----| 15 -> [RegExpPlus] (e+)+ #-----| 16 -> [RegExpConstant, RegExpNormalChar] f -# 422| [RegExpGroup] (e+) -#-----| 0 -> [RegExpPlus] e+ - -# 422| [RegExpPlus] (e+)+ -#-----| 0 -> [RegExpGroup] (e+) - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpConstant, RegExpNormalChar] 0 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpAlt] 0|1 -#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] 1 - -# 422| [RegExpConstant, RegExpNormalChar] ; - # 422| [RegExpCaret] ^ # 422| [RegExpAlt] ^|; #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpConstant, RegExpNormalChar] ; +# 422| [RegExpConstant, RegExpNormalChar] ; + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (0|1) +#-----| 0 -> [RegExpAlt] 0|1 + +# 422| [RegExpConstant, RegExpNormalChar] 0 + +# 422| [RegExpAlt] 0|1 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpConstant, RegExpNormalChar] 1 + +# 422| [RegExpGroup] (e+) +#-----| 0 -> [RegExpPlus] e+ + +# 422| [RegExpPlus] (e+)+ +#-----| 0 -> [RegExpGroup] (e+) + # 422| [RegExpConstant, RegExpNormalChar] e # 422| [RegExpPlus] e+ @@ -4597,14 +4597,6 @@ redos_variants.swift: # 422| [RegExpConstant, RegExpNormalChar] f -# 426| [RegExpDollar] $ - -# 426| [RegExpGroup] (c+) -#-----| 0 -> [RegExpPlus] c+ - -# 426| [RegExpPlus] (c+)+ -#-----| 0 -> [RegExpGroup] (c+) - # 426| [RegExpCaret] ^ # 426| [RegExpSequence] ^ab(c+)+$ @@ -4615,36 +4607,42 @@ redos_variants.swift: # 426| [RegExpConstant, RegExpNormalChar] ab +# 426| [RegExpGroup] (c+) +#-----| 0 -> [RegExpPlus] c+ + +# 426| [RegExpPlus] (c+)+ +#-----| 0 -> [RegExpGroup] (c+) + # 426| [RegExpConstant, RegExpNormalChar] c # 426| [RegExpPlus] c+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] c +# 426| [RegExpDollar] $ + # 430| [RegExpGroup] (\d(\s+)*) #-----| 0 -> [RegExpSequence] \d(\s+)* # 430| [RegExpRange] (\d(\s+)*){20} #-----| 0 -> [RegExpGroup] (\d(\s+)*) -# 430| [RegExpGroup] (\s+) -#-----| 0 -> [RegExpPlus] \s+ - -# 430| [RegExpStar] (\s+)* -#-----| 0 -> [RegExpGroup] (\s+) - # 430| [RegExpCharacterClassEscape] \d # 430| [RegExpSequence] \d(\s+)* #-----| 0 -> [RegExpCharacterClassEscape] \d #-----| 1 -> [RegExpStar] (\s+)* +# 430| [RegExpGroup] (\s+) +#-----| 0 -> [RegExpPlus] \s+ + +# 430| [RegExpStar] (\s+)* +#-----| 0 -> [RegExpGroup] (\s+) + # 430| [RegExpCharacterClassEscape] \s # 430| [RegExpPlus] \s+ #-----| 0 -> [RegExpCharacterClassEscape] \s -# 433| [RegExpDollar] $ - # 433| [RegExpGroup] (([^/]|X)+) #-----| 0 -> [RegExpPlus] ([^/]|X)+ @@ -4659,15 +4657,28 @@ redos_variants.swift: # 433| [RegExpPlus] ([^/]|X)+ #-----| 0 -> [RegExpGroup] ([^/]|X) +# 433| [RegExpCharacterClass] [^/] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] / + +# 433| [RegExpAlt] [^/]|X +#-----| 0 -> [RegExpCharacterClass] [^/] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] X + +# 433| [RegExpConstant, RegExpNormalChar] / + +# 433| [RegExpConstant, RegExpNormalChar] X + # 433| [RegExpGroup] (\/[\s\S]*) #-----| 0 -> [RegExpSequence] \/[\s\S]* # 433| [RegExpStar] (\/[\s\S]*)* #-----| 0 -> [RegExpGroup] (\/[\s\S]*) -# 433| [RegExpConstant, RegExpNormalChar] / +# 433| [RegExpConstant, RegExpEscape] \/ -# 433| [RegExpConstant, RegExpNormalChar] X +# 433| [RegExpSequence] \/[\s\S]* +#-----| 0 -> [RegExpConstant, RegExpEscape] \/ +#-----| 1 -> [RegExpStar] [\s\S]* # 433| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s @@ -4676,37 +4687,21 @@ redos_variants.swift: # 433| [RegExpStar] [\s\S]* #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 433| [RegExpCharacterClass] [^/] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] / - -# 433| [RegExpAlt] [^/]|X -#-----| 0 -> [RegExpCharacterClass] [^/] -#-----| 1 -> [RegExpConstant, RegExpNormalChar] X - -# 433| [RegExpConstant, RegExpEscape] \/ - -# 433| [RegExpSequence] \/[\s\S]* -#-----| 0 -> [RegExpConstant, RegExpEscape] \/ -#-----| 1 -> [RegExpStar] [\s\S]* +# 433| [RegExpCharacterClassEscape] \s # 433| [RegExpCharacterClassEscape] \S -# 433| [RegExpCharacterClassEscape] \s +# 433| [RegExpDollar] $ -# 436| [RegExpDollar] $ +# 436| [RegExpCaret] ^ + +# 436| [RegExpSequence] ^((x([^Y]+)?)*(Y|$)) +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpGroup] ((x([^Y]+)?)*(Y|$)) # 436| [RegExpGroup] ((x([^Y]+)?)*(Y|$)) #-----| 0 -> [RegExpSequence] (x([^Y]+)?)*(Y|$) -# 436| [RegExpGroup] (Y|$) -#-----| 0 -> [RegExpAlt] Y|$ - -# 436| [RegExpGroup] ([^Y]+) -#-----| 0 -> [RegExpPlus] [^Y]+ - -# 436| [RegExpOpt] ([^Y]+)? -#-----| 0 -> [RegExpGroup] ([^Y]+) - # 436| [RegExpGroup] (x([^Y]+)?) #-----| 0 -> [RegExpSequence] x([^Y]+)? @@ -4717,13 +4712,17 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] (x([^Y]+)?)* #-----| 1 -> [RegExpGroup] (Y|$) -# 436| [RegExpConstant, RegExpNormalChar] Y +# 436| [RegExpConstant, RegExpNormalChar] x -# 436| [RegExpConstant, RegExpNormalChar] Y +# 436| [RegExpSequence] x([^Y]+)? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] x +#-----| 1 -> [RegExpOpt] ([^Y]+)? -# 436| [RegExpAlt] Y|$ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] Y -#-----| 1 -> [RegExpDollar] $ +# 436| [RegExpGroup] ([^Y]+) +#-----| 0 -> [RegExpPlus] [^Y]+ + +# 436| [RegExpOpt] ([^Y]+)? +#-----| 0 -> [RegExpGroup] ([^Y]+) # 436| [RegExpCharacterClass] [^Y] #-----| 0 -> [RegExpConstant, RegExpNormalChar] Y @@ -4731,17 +4730,25 @@ redos_variants.swift: # 436| [RegExpPlus] [^Y]+ #-----| 0 -> [RegExpCharacterClass] [^Y] -# 436| [RegExpCaret] ^ +# 436| [RegExpConstant, RegExpNormalChar] Y -# 436| [RegExpSequence] ^((x([^Y]+)?)*(Y|$)) -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpGroup] ((x([^Y]+)?)*(Y|$)) +# 436| [RegExpGroup] (Y|$) +#-----| 0 -> [RegExpAlt] Y|$ -# 436| [RegExpConstant, RegExpNormalChar] x +# 436| [RegExpConstant, RegExpNormalChar] Y -# 436| [RegExpSequence] x([^Y]+)? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] x -#-----| 1 -> [RegExpOpt] ([^Y]+)? +# 436| [RegExpAlt] Y|$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] Y +#-----| 1 -> [RegExpDollar] $ + +# 436| [RegExpDollar] $ + +# 440| [RegExpConstant, RegExpNormalChar] foo + +# 440| [RegExpSequence] foo([\w-]*)+bar +#-----| 0 -> [RegExpConstant, RegExpNormalChar] foo +#-----| 1 -> [RegExpPlus] ([\w-]*)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] bar # 440| [RegExpGroup] ([\w-]*) #-----| 0 -> [RegExpStar] [\w-]* @@ -4749,8 +4756,6 @@ redos_variants.swift: # 440| [RegExpPlus] ([\w-]*)+ #-----| 0 -> [RegExpGroup] ([\w-]*) -# 440| [RegExpConstant, RegExpNormalChar] - - # 440| [RegExpCharacterClass] [\w-] #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpNormalChar] - @@ -4760,15 +4765,10 @@ redos_variants.swift: # 440| [RegExpCharacterClassEscape] \w +# 440| [RegExpConstant, RegExpNormalChar] - + # 440| [RegExpConstant, RegExpNormalChar] bar -# 440| [RegExpConstant, RegExpNormalChar] foo - -# 440| [RegExpSequence] foo([\w-]*)+bar -#-----| 0 -> [RegExpConstant, RegExpNormalChar] foo -#-----| 1 -> [RegExpPlus] ([\w-]*)+ -#-----| 2 -> [RegExpConstant, RegExpNormalChar] bar - # 444| [RegExpGroup] ((ab)*) #-----| 0 -> [RegExpStar] (ab)* @@ -4801,11 +4801,6 @@ redos_variants.swift: # 448| [RegExpConstant, RegExpNormalChar] a -# 448| [RegExpConstant, RegExpNormalChar] a - -# 448| [RegExpOpt] a? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a - # 448| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a @@ -4813,6 +4808,11 @@ redos_variants.swift: #-----| 0 -> [RegExpOpt] a? #-----| 1 -> [RegExpOpt] a? +# 448| [RegExpConstant, RegExpNormalChar] a + +# 448| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + # 448| [RegExpConstant, RegExpNormalChar] b # 451| [RegExpGroup] (a?) @@ -4842,13 +4842,6 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] (c?a?)* #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 455| [RegExpConstant, RegExpNormalChar] a - -# 455| [RegExpOpt] a? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a - -# 455| [RegExpConstant, RegExpNormalChar] b - # 455| [RegExpConstant, RegExpNormalChar] c # 455| [RegExpOpt] c? @@ -4858,6 +4851,13 @@ redos_variants.swift: #-----| 0 -> [RegExpOpt] c? #-----| 1 -> [RegExpOpt] a? +# 455| [RegExpConstant, RegExpNormalChar] a + +# 455| [RegExpOpt] a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 455| [RegExpConstant, RegExpNormalChar] b + # 459| [RegExpGroup] (?:a|a?) #-----| 0 -> [RegExpAlt] a|a? @@ -4870,19 +4870,17 @@ redos_variants.swift: # 459| [RegExpConstant, RegExpNormalChar] a +# 459| [RegExpAlt] a|a? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpOpt] a? + # 459| [RegExpConstant, RegExpNormalChar] a # 459| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 459| [RegExpAlt] a|a? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -#-----| 1 -> [RegExpOpt] a? - # 459| [RegExpConstant, RegExpNormalChar] b -# 463| [RegExpDollar] $ - # 463| [RegExpGroup] (a?b?) #-----| 0 -> [RegExpSequence] a?b? @@ -4907,7 +4905,14 @@ redos_variants.swift: # 463| [RegExpOpt] b? #-----| 0 -> [RegExpConstant, RegExpNormalChar] b -# 467| [RegExpDollar] $ +# 463| [RegExpDollar] $ + +# 467| [RegExpConstant, RegExpNormalChar] PRE + +# 467| [RegExpSequence] PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] PRE +#-----| 1 -> [RegExpPlus] (([a-c]|[c-d])T(e?e?e?e?|X))+ +#-----| 2 -> [RegExpGroup] (cTcT|cTXcTX$) # 467| [RegExpGroup] (([a-c]|[c-d])T(e?e?e?e?|X)) #-----| 0 -> [RegExpSequence] ([a-c]|[c-d])T(e?e?e?e?|X) @@ -4923,23 +4928,6 @@ redos_variants.swift: #-----| 1 -> [RegExpConstant, RegExpNormalChar] T #-----| 2 -> [RegExpGroup] (e?e?e?e?|X) -# 467| [RegExpGroup] (cTcT|cTXcTX$) -#-----| 0 -> [RegExpAlt] cTcT|cTXcTX$ - -# 467| [RegExpGroup] (e?e?e?e?|X) -#-----| 0 -> [RegExpAlt] e?e?e?e?|X - -# 467| [RegExpConstant, RegExpNormalChar] PRE - -# 467| [RegExpSequence] PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$) -#-----| 0 -> [RegExpConstant, RegExpNormalChar] PRE -#-----| 1 -> [RegExpPlus] (([a-c]|[c-d])T(e?e?e?e?|X))+ -#-----| 2 -> [RegExpGroup] (cTcT|cTXcTX$) - -# 467| [RegExpConstant, RegExpNormalChar] T - -# 467| [RegExpConstant, RegExpNormalChar] X - # 467| [RegExpCharacterClass] [a-c] #-----| 0 -> [RegExpCharacterRange] a-c @@ -4947,9 +4935,6 @@ redos_variants.swift: #-----| 0 -> [RegExpCharacterClass] [a-c] #-----| 1 -> [RegExpCharacterClass] [c-d] -# 467| [RegExpCharacterClass] [c-d] -#-----| 0 -> [RegExpCharacterRange] c-d - # 467| [RegExpConstant, RegExpNormalChar] a # 467| [RegExpCharacterRange] a-c @@ -4958,43 +4943,24 @@ redos_variants.swift: # 467| [RegExpConstant, RegExpNormalChar] c +# 467| [RegExpCharacterClass] [c-d] +#-----| 0 -> [RegExpCharacterRange] c-d + # 467| [RegExpConstant, RegExpNormalChar] c # 467| [RegExpCharacterRange] c-d #-----| 0 -> [RegExpConstant, RegExpNormalChar] c #-----| 1 -> [RegExpConstant, RegExpNormalChar] d -# 467| [RegExpConstant, RegExpNormalChar] cTXcTX - -# 467| [RegExpSequence] cTXcTX$ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] cTXcTX -#-----| 1 -> [RegExpDollar] $ - -# 467| [RegExpConstant, RegExpNormalChar] cTcT - -# 467| [RegExpAlt] cTcT|cTXcTX$ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] cTcT -#-----| 1 -> [RegExpSequence] cTXcTX$ - # 467| [RegExpConstant, RegExpNormalChar] d -# 467| [RegExpConstant, RegExpNormalChar] e +# 467| [RegExpConstant, RegExpNormalChar] T + +# 467| [RegExpGroup] (e?e?e?e?|X) +#-----| 0 -> [RegExpAlt] e?e?e?e?|X # 467| [RegExpConstant, RegExpNormalChar] e -# 467| [RegExpConstant, RegExpNormalChar] e - -# 467| [RegExpConstant, RegExpNormalChar] e - -# 467| [RegExpOpt] e? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] e - -# 467| [RegExpOpt] e? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] e - -# 467| [RegExpOpt] e? -#-----| 0 -> [RegExpConstant, RegExpNormalChar] e - # 467| [RegExpOpt] e? #-----| 0 -> [RegExpConstant, RegExpNormalChar] e @@ -5008,7 +4974,46 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] e?e?e?e? #-----| 1 -> [RegExpConstant, RegExpNormalChar] X -# 471| [RegExpDollar] $ +# 467| [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpOpt] e? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpOpt] e? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpOpt] e? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] e + +# 467| [RegExpConstant, RegExpNormalChar] X + +# 467| [RegExpGroup] (cTcT|cTXcTX$) +#-----| 0 -> [RegExpAlt] cTcT|cTXcTX$ + +# 467| [RegExpConstant, RegExpNormalChar] cTcT + +# 467| [RegExpAlt] cTcT|cTXcTX$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] cTcT +#-----| 1 -> [RegExpSequence] cTXcTX$ + +# 467| [RegExpConstant, RegExpNormalChar] cTXcTX + +# 467| [RegExpSequence] cTXcTX$ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] cTXcTX +#-----| 1 -> [RegExpDollar] $ + +# 467| [RegExpDollar] $ + +# 471| [RegExpCaret] ^ + +# 471| [RegExpSequence] ^((a)+\w)+$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ((a)+\w)+ +#-----| 2 -> [RegExpDollar] $ # 471| [RegExpGroup] ((a)+\w) #-----| 0 -> [RegExpSequence] (a)+\w @@ -5026,26 +5031,11 @@ redos_variants.swift: #-----| 0 -> [RegExpPlus] (a)+ #-----| 1 -> [RegExpCharacterClassEscape] \w -# 471| [RegExpCharacterClassEscape] \w - -# 471| [RegExpCaret] ^ - -# 471| [RegExpSequence] ^((a)+\w)+$ -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpPlus] ((a)+\w)+ -#-----| 2 -> [RegExpDollar] $ - # 471| [RegExpConstant, RegExpNormalChar] a -# 475| [RegExpDollar] $ +# 471| [RegExpCharacterClassEscape] \w -# 475| [RegExpGroup] (b+.) -#-----| 0 -> [RegExpSequence] b+. - -# 475| [RegExpPlus] (b+.)+ -#-----| 0 -> [RegExpGroup] (b+.) - -# 475| [RegExpDot] . +# 471| [RegExpDollar] $ # 475| [RegExpCaret] ^ @@ -5054,6 +5044,12 @@ redos_variants.swift: #-----| 1 -> [RegExpPlus] (b+.)+ #-----| 2 -> [RegExpDollar] $ +# 475| [RegExpGroup] (b+.) +#-----| 0 -> [RegExpSequence] b+. + +# 475| [RegExpPlus] (b+.)+ +#-----| 0 -> [RegExpGroup] (b+.) + # 475| [RegExpConstant, RegExpNormalChar] b # 475| [RegExpPlus] b+ @@ -5063,6 +5059,10 @@ redos_variants.swift: #-----| 0 -> [RegExpPlus] b+ #-----| 1 -> [RegExpDot] . +# 475| [RegExpDot] . + +# 475| [RegExpDollar] $ + # 479| [RegExpGroup] (a*) #-----| 0 -> [RegExpStar] a* @@ -5145,50 +5145,12 @@ redos_variants.swift: # 485| [RegExpConstant, RegExpNormalChar] b -# 488| [RegExpConstant, RegExpNormalChar] " - -# 488| [RegExpConstant, RegExpNormalChar] ' - -# 488| [RegExpConstant, RegExpNormalChar] ( - -# 488| [RegExpNegativeLookahead] (?![/\\]) - # 488| [RegExpGroup] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\])) #-----| 0 -> [RegExpAlt] [\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]) # 488| [RegExpPlus] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]))+ #-----| 0 -> [RegExpGroup] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\])) -# 488| [RegExpConstant, RegExpNormalChar] ) - -# 488| [RegExpConstant, RegExpNormalChar] * - -# 488| [RegExpConstant, RegExpNormalChar] + - -# 488| [RegExpConstant, RegExpNormalChar] , - -# 488| [RegExpConstant, RegExpNormalChar] / - -# 488| [RegExpConstant, RegExpNormalChar] : - -# 488| [RegExpSequence] :(?![/\\]) -#-----| 0 -> [RegExpConstant, RegExpNormalChar] : -#-----| 1 -> [RegExpNegativeLookahead] (?![/\\]) - -# 488| [RegExpConstant, RegExpNormalChar] ; - -# 488| [RegExpConstant, RegExpNormalChar] < - -# 488| [RegExpConstant, RegExpNormalChar] = - -# 488| [RegExpConstant, RegExpNormalChar] > - -# 488| [RegExpConstant, RegExpNormalChar] @ - -# 488| [RegExpCharacterClass] [/\\] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] / -#-----| 1 -> [RegExpConstant, RegExpEscape] \\ - # 488| [RegExpCharacterClass] [\s;,"'<>(){}|\[\]@=+*] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpConstant, RegExpNormalChar] ; @@ -5213,21 +5175,65 @@ redos_variants.swift: #-----| 0 -> [RegExpCharacterClass] [\s;,"'<>(){}|\[\]@=+*] #-----| 1 -> [RegExpSequence] :(?![/\\]) -# 488| [RegExpConstant, RegExpEscape] \[ - -# 488| [RegExpConstant, RegExpEscape] \\ - -# 488| [RegExpConstant, RegExpEscape] \] - # 488| [RegExpCharacterClassEscape] \s +# 488| [RegExpConstant, RegExpNormalChar] ; + +# 488| [RegExpConstant, RegExpNormalChar] , + +# 488| [RegExpConstant, RegExpNormalChar] " + +# 488| [RegExpConstant, RegExpNormalChar] ' + +# 488| [RegExpConstant, RegExpNormalChar] < + +# 488| [RegExpConstant, RegExpNormalChar] > + +# 488| [RegExpConstant, RegExpNormalChar] ( + +# 488| [RegExpConstant, RegExpNormalChar] ) + # 488| [RegExpConstant, RegExpNormalChar] { -# 488| [RegExpConstant, RegExpNormalChar] | - # 488| [RegExpConstant, RegExpNormalChar] } -# 492| [RegExpDollar] $ +# 488| [RegExpConstant, RegExpNormalChar] | + +# 488| [RegExpConstant, RegExpEscape] \[ + +# 488| [RegExpConstant, RegExpEscape] \] + +# 488| [RegExpConstant, RegExpNormalChar] @ + +# 488| [RegExpConstant, RegExpNormalChar] = + +# 488| [RegExpConstant, RegExpNormalChar] + + +# 488| [RegExpConstant, RegExpNormalChar] * + +# 488| [RegExpConstant, RegExpNormalChar] : + +# 488| [RegExpSequence] :(?![/\\]) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] : +#-----| 1 -> [RegExpNegativeLookahead] (?![/\\]) + +# 488| [RegExpNegativeLookahead] (?![/\\]) + +# 488| [RegExpCharacterClass] [/\\] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] / +#-----| 1 -> [RegExpConstant, RegExpEscape] \\ + +# 488| [RegExpConstant, RegExpNormalChar] / + +# 488| [RegExpConstant, RegExpEscape] \\ + +# 492| [RegExpCaret] ^ + +# 492| [RegExpSequence] ^((?:a{|-)|\w\{)+X$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ((?:a{|-)|\w\{)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] X +#-----| 3 -> [RegExpDollar] $ # 492| [RegExpGroup] ((?:a{|-)|\w\{) #-----| 0 -> [RegExpAlt] (?:a{|-)|\w\{ @@ -5242,9 +5248,13 @@ redos_variants.swift: #-----| 0 -> [RegExpGroup] (?:a{|-) #-----| 1 -> [RegExpSequence] \w\{ -# 492| [RegExpConstant, RegExpNormalChar] - +# 492| [RegExpConstant, RegExpNormalChar] a{ -# 492| [RegExpConstant, RegExpNormalChar] X +# 492| [RegExpAlt] a{|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + +# 492| [RegExpConstant, RegExpNormalChar] - # 492| [RegExpCharacterClassEscape] \w @@ -5254,22 +5264,18 @@ redos_variants.swift: # 492| [RegExpConstant, RegExpEscape] \{ -# 492| [RegExpCaret] ^ +# 492| [RegExpConstant, RegExpNormalChar] X -# 492| [RegExpSequence] ^((?:a{|-)|\w\{)+X$ +# 492| [RegExpDollar] $ + +# 493| [RegExpCaret] ^ + +# 493| [RegExpSequence] ^((?:a{0|-)|\w\{\d)+X$ #-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpPlus] ((?:a{|-)|\w\{)+ +#-----| 1 -> [RegExpPlus] ((?:a{0|-)|\w\{\d)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] X #-----| 3 -> [RegExpDollar] $ -# 492| [RegExpConstant, RegExpNormalChar] a{ - -# 492| [RegExpAlt] a{|- -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{ -#-----| 1 -> [RegExpConstant, RegExpNormalChar] - - -# 493| [RegExpDollar] $ - # 493| [RegExpGroup] ((?:a{0|-)|\w\{\d) #-----| 0 -> [RegExpAlt] (?:a{0|-)|\w\{\d @@ -5283,12 +5289,14 @@ redos_variants.swift: #-----| 0 -> [RegExpGroup] (?:a{0|-) #-----| 1 -> [RegExpSequence] \w\{\d +# 493| [RegExpConstant, RegExpNormalChar] a{0 + +# 493| [RegExpAlt] a{0|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + # 493| [RegExpConstant, RegExpNormalChar] - -# 493| [RegExpConstant, RegExpNormalChar] X - -# 493| [RegExpCharacterClassEscape] \d - # 493| [RegExpCharacterClassEscape] \w # 493| [RegExpSequence] \w\{\d @@ -5298,22 +5306,20 @@ redos_variants.swift: # 493| [RegExpConstant, RegExpEscape] \{ -# 493| [RegExpCaret] ^ +# 493| [RegExpCharacterClassEscape] \d -# 493| [RegExpSequence] ^((?:a{0|-)|\w\{\d)+X$ +# 493| [RegExpConstant, RegExpNormalChar] X + +# 493| [RegExpDollar] $ + +# 494| [RegExpCaret] ^ + +# 494| [RegExpSequence] ^((?:a{0,|-)|\w\{\d,)+X$ #-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpPlus] ((?:a{0|-)|\w\{\d)+ +#-----| 1 -> [RegExpPlus] ((?:a{0,|-)|\w\{\d,)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] X #-----| 3 -> [RegExpDollar] $ -# 493| [RegExpConstant, RegExpNormalChar] a{0 - -# 493| [RegExpAlt] a{0|- -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] - - -# 494| [RegExpDollar] $ - # 494| [RegExpGroup] ((?:a{0,|-)|\w\{\d,) #-----| 0 -> [RegExpAlt] (?:a{0,|-)|\w\{\d, @@ -5327,14 +5333,14 @@ redos_variants.swift: #-----| 0 -> [RegExpGroup] (?:a{0,|-) #-----| 1 -> [RegExpSequence] \w\{\d, -# 494| [RegExpConstant, RegExpNormalChar] , +# 494| [RegExpConstant, RegExpNormalChar] a{0, + +# 494| [RegExpAlt] a{0,|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0, +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - # 494| [RegExpConstant, RegExpNormalChar] - -# 494| [RegExpConstant, RegExpNormalChar] X - -# 494| [RegExpCharacterClassEscape] \d - # 494| [RegExpCharacterClassEscape] \w # 494| [RegExpSequence] \w\{\d, @@ -5345,22 +5351,22 @@ redos_variants.swift: # 494| [RegExpConstant, RegExpEscape] \{ -# 494| [RegExpCaret] ^ +# 494| [RegExpCharacterClassEscape] \d -# 494| [RegExpSequence] ^((?:a{0,|-)|\w\{\d,)+X$ +# 494| [RegExpConstant, RegExpNormalChar] , + +# 494| [RegExpConstant, RegExpNormalChar] X + +# 494| [RegExpDollar] $ + +# 495| [RegExpCaret] ^ + +# 495| [RegExpSequence] ^((?:a{0,2|-)|\w\{\d,\d)+X$ #-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpPlus] ((?:a{0,|-)|\w\{\d,)+ +#-----| 1 -> [RegExpPlus] ((?:a{0,2|-)|\w\{\d,\d)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] X #-----| 3 -> [RegExpDollar] $ -# 494| [RegExpConstant, RegExpNormalChar] a{0, - -# 494| [RegExpAlt] a{0,|- -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0, -#-----| 1 -> [RegExpConstant, RegExpNormalChar] - - -# 495| [RegExpDollar] $ - # 495| [RegExpGroup] ((?:a{0,2|-)|\w\{\d,\d) #-----| 0 -> [RegExpAlt] (?:a{0,2|-)|\w\{\d,\d @@ -5374,16 +5380,14 @@ redos_variants.swift: #-----| 0 -> [RegExpGroup] (?:a{0,2|-) #-----| 1 -> [RegExpSequence] \w\{\d,\d -# 495| [RegExpConstant, RegExpNormalChar] , +# 495| [RegExpConstant, RegExpNormalChar] a{0,2 + +# 495| [RegExpAlt] a{0,2|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0,2 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - # 495| [RegExpConstant, RegExpNormalChar] - -# 495| [RegExpConstant, RegExpNormalChar] X - -# 495| [RegExpCharacterClassEscape] \d - -# 495| [RegExpCharacterClassEscape] \d - # 495| [RegExpCharacterClassEscape] \w # 495| [RegExpSequence] \w\{\d,\d @@ -5395,22 +5399,24 @@ redos_variants.swift: # 495| [RegExpConstant, RegExpEscape] \{ -# 495| [RegExpCaret] ^ +# 495| [RegExpCharacterClassEscape] \d -# 495| [RegExpSequence] ^((?:a{0,2|-)|\w\{\d,\d)+X$ +# 495| [RegExpConstant, RegExpNormalChar] , + +# 495| [RegExpCharacterClassEscape] \d + +# 495| [RegExpConstant, RegExpNormalChar] X + +# 495| [RegExpDollar] $ + +# 498| [RegExpCaret] ^ + +# 498| [RegExpSequence] ^((?:a{0,2}|-)|\w\{\d,\d\})+X$ #-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpPlus] ((?:a{0,2|-)|\w\{\d,\d)+ +#-----| 1 -> [RegExpPlus] ((?:a{0,2}|-)|\w\{\d,\d\})+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] X #-----| 3 -> [RegExpDollar] $ -# 495| [RegExpConstant, RegExpNormalChar] a{0,2 - -# 495| [RegExpAlt] a{0,2|- -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0,2 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] - - -# 498| [RegExpDollar] $ - # 498| [RegExpGroup] ((?:a{0,2}|-)|\w\{\d,\d\}) #-----| 0 -> [RegExpAlt] (?:a{0,2}|-)|\w\{\d,\d\} @@ -5424,16 +5430,17 @@ redos_variants.swift: #-----| 0 -> [RegExpGroup] (?:a{0,2}|-) #-----| 1 -> [RegExpSequence] \w\{\d,\d\} -# 498| [RegExpConstant, RegExpNormalChar] , +# 498| [RegExpConstant, RegExpNormalChar] a + +# 498| [RegExpRange] a{0,2} +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 498| [RegExpAlt] a{0,2}|- +#-----| 0 -> [RegExpRange] a{0,2} +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - # 498| [RegExpConstant, RegExpNormalChar] - -# 498| [RegExpConstant, RegExpNormalChar] X - -# 498| [RegExpCharacterClassEscape] \d - -# 498| [RegExpCharacterClassEscape] \d - # 498| [RegExpCharacterClassEscape] \w # 498| [RegExpSequence] \w\{\d,\d\} @@ -5446,30 +5453,17 @@ redos_variants.swift: # 498| [RegExpConstant, RegExpEscape] \{ +# 498| [RegExpCharacterClassEscape] \d + +# 498| [RegExpConstant, RegExpNormalChar] , + +# 498| [RegExpCharacterClassEscape] \d + # 498| [RegExpConstant, RegExpEscape] \} -# 498| [RegExpCaret] ^ +# 498| [RegExpConstant, RegExpNormalChar] X -# 498| [RegExpSequence] ^((?:a{0,2}|-)|\w\{\d,\d\})+X$ -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpPlus] ((?:a{0,2}|-)|\w\{\d,\d\})+ -#-----| 2 -> [RegExpConstant, RegExpNormalChar] X -#-----| 3 -> [RegExpDollar] $ - -# 498| [RegExpConstant, RegExpNormalChar] a - -# 498| [RegExpRange] a{0,2} -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a - -# 498| [RegExpAlt] a{0,2}|- -#-----| 0 -> [RegExpRange] a{0,2} -#-----| 1 -> [RegExpConstant, RegExpNormalChar] - - -# 502| [RegExpGroup] (\u0061|a) -#-----| 0 -> [RegExpAlt] \u0061|a - -# 502| [RegExpStar] (\u0061|a)* -#-----| 0 -> [RegExpGroup] (\u0061|a) +# 498| [RegExpDollar] $ # 502| [RegExpConstant, RegExpNormalChar] X @@ -5478,7 +5472,11 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\u0061|a)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 502| [RegExpConstant, RegExpNormalChar] Y +# 502| [RegExpGroup] (\u0061|a) +#-----| 0 -> [RegExpAlt] \u0061|a + +# 502| [RegExpStar] (\u0061|a)* +#-----| 0 -> [RegExpGroup] (\u0061|a) # 502| [RegExpConstant, RegExpEscape] \u0061 @@ -5488,11 +5486,7 @@ redos_variants.swift: # 502| [RegExpConstant, RegExpNormalChar] a -# 505| [RegExpGroup] (\u0061|b) -#-----| 0 -> [RegExpAlt] \u0061|b - -# 505| [RegExpPlus] (\u0061|b)+ -#-----| 0 -> [RegExpGroup] (\u0061|b) +# 502| [RegExpConstant, RegExpNormalChar] Y # 505| [RegExpConstant, RegExpNormalChar] X @@ -5501,7 +5495,11 @@ redos_variants.swift: #-----| 1 -> [RegExpPlus] (\u0061|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 505| [RegExpConstant, RegExpNormalChar] Y +# 505| [RegExpGroup] (\u0061|b) +#-----| 0 -> [RegExpAlt] \u0061|b + +# 505| [RegExpPlus] (\u0061|b)+ +#-----| 0 -> [RegExpGroup] (\u0061|b) # 505| [RegExpConstant, RegExpEscape] \u0061 @@ -5511,11 +5509,7 @@ redos_variants.swift: # 505| [RegExpConstant, RegExpNormalChar] b -# 509| [RegExpGroup] (\U00000061|a) -#-----| 0 -> [RegExpAlt] \U00000061|a - -# 509| [RegExpStar] (\U00000061|a)* -#-----| 0 -> [RegExpGroup] (\U00000061|a) +# 505| [RegExpConstant, RegExpNormalChar] Y # 509| [RegExpConstant, RegExpNormalChar] X @@ -5524,7 +5518,11 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\U00000061|a)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 509| [RegExpConstant, RegExpNormalChar] Y +# 509| [RegExpGroup] (\U00000061|a) +#-----| 0 -> [RegExpAlt] \U00000061|a + +# 509| [RegExpStar] (\U00000061|a)* +#-----| 0 -> [RegExpGroup] (\U00000061|a) # 509| [RegExpConstant, RegExpEscape] \U00000061 @@ -5534,11 +5532,7 @@ redos_variants.swift: # 509| [RegExpConstant, RegExpNormalChar] a -# 512| [RegExpGroup] (\U00000061|b) -#-----| 0 -> [RegExpAlt] \U00000061|b - -# 512| [RegExpPlus] (\U00000061|b)+ -#-----| 0 -> [RegExpGroup] (\U00000061|b) +# 509| [RegExpConstant, RegExpNormalChar] Y # 512| [RegExpConstant, RegExpNormalChar] X @@ -5547,7 +5541,11 @@ redos_variants.swift: #-----| 1 -> [RegExpPlus] (\U00000061|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 512| [RegExpConstant, RegExpNormalChar] Y +# 512| [RegExpGroup] (\U00000061|b) +#-----| 0 -> [RegExpAlt] \U00000061|b + +# 512| [RegExpPlus] (\U00000061|b)+ +#-----| 0 -> [RegExpGroup] (\U00000061|b) # 512| [RegExpConstant, RegExpEscape] \U00000061 @@ -5557,11 +5555,7 @@ redos_variants.swift: # 512| [RegExpConstant, RegExpNormalChar] b -# 516| [RegExpGroup] (\x61|a) -#-----| 0 -> [RegExpAlt] \x61|a - -# 516| [RegExpStar] (\x61|a)* -#-----| 0 -> [RegExpGroup] (\x61|a) +# 512| [RegExpConstant, RegExpNormalChar] Y # 516| [RegExpConstant, RegExpNormalChar] X @@ -5570,7 +5564,11 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\x61|a)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 516| [RegExpConstant, RegExpNormalChar] Y +# 516| [RegExpGroup] (\x61|a) +#-----| 0 -> [RegExpAlt] \x61|a + +# 516| [RegExpStar] (\x61|a)* +#-----| 0 -> [RegExpGroup] (\x61|a) # 516| [RegExpConstant, RegExpEscape] \x61 @@ -5580,11 +5578,7 @@ redos_variants.swift: # 516| [RegExpConstant, RegExpNormalChar] a -# 519| [RegExpGroup] (\x61|b) -#-----| 0 -> [RegExpAlt] \x61|b - -# 519| [RegExpPlus] (\x61|b)+ -#-----| 0 -> [RegExpGroup] (\x61|b) +# 516| [RegExpConstant, RegExpNormalChar] Y # 519| [RegExpConstant, RegExpNormalChar] X @@ -5593,7 +5587,11 @@ redos_variants.swift: #-----| 1 -> [RegExpPlus] (\x61|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 519| [RegExpConstant, RegExpNormalChar] Y +# 519| [RegExpGroup] (\x61|b) +#-----| 0 -> [RegExpAlt] \x61|b + +# 519| [RegExpPlus] (\x61|b)+ +#-----| 0 -> [RegExpGroup] (\x61|b) # 519| [RegExpConstant, RegExpEscape] \x61 @@ -5603,11 +5601,7 @@ redos_variants.swift: # 519| [RegExpConstant, RegExpNormalChar] b -# 523| [RegExpGroup] (\x{061}|a) -#-----| 0 -> [RegExpAlt] \x{061}|a - -# 523| [RegExpStar] (\x{061}|a)* -#-----| 0 -> [RegExpGroup] (\x{061}|a) +# 519| [RegExpConstant, RegExpNormalChar] Y # 523| [RegExpConstant, RegExpNormalChar] X @@ -5616,7 +5610,11 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\x{061}|a)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 523| [RegExpConstant, RegExpNormalChar] Y +# 523| [RegExpGroup] (\x{061}|a) +#-----| 0 -> [RegExpAlt] \x{061}|a + +# 523| [RegExpStar] (\x{061}|a)* +#-----| 0 -> [RegExpGroup] (\x{061}|a) # 523| [RegExpConstant, RegExpEscape] \x{0 @@ -5629,11 +5627,7 @@ redos_variants.swift: # 523| [RegExpConstant, RegExpNormalChar] a -# 526| [RegExpGroup] (\x{061}|b) -#-----| 0 -> [RegExpAlt] \x{061}|b - -# 526| [RegExpPlus] (\x{061}|b)+ -#-----| 0 -> [RegExpGroup] (\x{061}|b) +# 523| [RegExpConstant, RegExpNormalChar] Y # 526| [RegExpConstant, RegExpNormalChar] X @@ -5642,7 +5636,11 @@ redos_variants.swift: #-----| 1 -> [RegExpPlus] (\x{061}|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 526| [RegExpConstant, RegExpNormalChar] Y +# 526| [RegExpGroup] (\x{061}|b) +#-----| 0 -> [RegExpAlt] \x{061}|b + +# 526| [RegExpPlus] (\x{061}|b)+ +#-----| 0 -> [RegExpGroup] (\x{061}|b) # 526| [RegExpConstant, RegExpEscape] \x{0 @@ -5655,13 +5653,7 @@ redos_variants.swift: # 526| [RegExpConstant, RegExpNormalChar] b -# 530| [RegExpGroup] (\p{Digit}|7) -#-----| 0 -> [RegExpAlt] \p{Digit}|7 - -# 530| [RegExpStar] (\p{Digit}|7)* -#-----| 0 -> [RegExpGroup] (\p{Digit}|7) - -# 530| [RegExpConstant, RegExpNormalChar] 7 +# 526| [RegExpConstant, RegExpNormalChar] Y # 530| [RegExpConstant, RegExpNormalChar] X @@ -5670,7 +5662,11 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\p{Digit}|7)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 530| [RegExpConstant, RegExpNormalChar] Y +# 530| [RegExpGroup] (\p{Digit}|7) +#-----| 0 -> [RegExpAlt] \p{Digit}|7 + +# 530| [RegExpStar] (\p{Digit}|7)* +#-----| 0 -> [RegExpGroup] (\p{Digit}|7) # 530| [RegExpNamedCharacterProperty] \p{Digit} @@ -5680,11 +5676,9 @@ redos_variants.swift: # 530| [RegExpAlt] |7 -# 533| [RegExpGroup] (\p{Digit}|b) -#-----| 0 -> [RegExpAlt] \p{Digit}|b +# 530| [RegExpConstant, RegExpNormalChar] 7 -# 533| [RegExpPlus] (\p{Digit}|b)+ -#-----| 0 -> [RegExpGroup] (\p{Digit}|b) +# 530| [RegExpConstant, RegExpNormalChar] Y # 533| [RegExpConstant, RegExpNormalChar] X @@ -5693,7 +5687,11 @@ redos_variants.swift: #-----| 1 -> [RegExpPlus] (\p{Digit}|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 533| [RegExpConstant, RegExpNormalChar] Y +# 533| [RegExpGroup] (\p{Digit}|b) +#-----| 0 -> [RegExpAlt] \p{Digit}|b + +# 533| [RegExpPlus] (\p{Digit}|b)+ +#-----| 0 -> [RegExpGroup] (\p{Digit}|b) # 533| [RegExpNamedCharacterProperty] \p{Digit} @@ -5701,15 +5699,11 @@ redos_variants.swift: #-----| 0 -> [RegExpNamedCharacterProperty] \p{Digit} #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 533| [RegExpConstant, RegExpNormalChar] b - # 533| [RegExpAlt] |b -# 537| [RegExpGroup] (\P{Digit}|b) -#-----| 0 -> [RegExpAlt] \P{Digit}|b +# 533| [RegExpConstant, RegExpNormalChar] b -# 537| [RegExpStar] (\P{Digit}|b)* -#-----| 0 -> [RegExpGroup] (\P{Digit}|b) +# 533| [RegExpConstant, RegExpNormalChar] Y # 537| [RegExpConstant, RegExpNormalChar] X @@ -5718,7 +5712,11 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\P{Digit}|b)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 537| [RegExpConstant, RegExpNormalChar] Y +# 537| [RegExpGroup] (\P{Digit}|b) +#-----| 0 -> [RegExpAlt] \P{Digit}|b + +# 537| [RegExpStar] (\P{Digit}|b)* +#-----| 0 -> [RegExpGroup] (\P{Digit}|b) # 537| [RegExpNamedCharacterProperty] \P{Digit} @@ -5726,17 +5724,11 @@ redos_variants.swift: #-----| 0 -> [RegExpNamedCharacterProperty] \P{Digit} #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 537| [RegExpConstant, RegExpNormalChar] b - # 537| [RegExpAlt] |b -# 540| [RegExpGroup] (\P{Digit}|7) -#-----| 0 -> [RegExpAlt] \P{Digit}|7 +# 537| [RegExpConstant, RegExpNormalChar] b -# 540| [RegExpPlus] (\P{Digit}|7)+ -#-----| 0 -> [RegExpGroup] (\P{Digit}|7) - -# 540| [RegExpConstant, RegExpNormalChar] 7 +# 537| [RegExpConstant, RegExpNormalChar] Y # 540| [RegExpConstant, RegExpNormalChar] X @@ -5745,7 +5737,11 @@ redos_variants.swift: #-----| 1 -> [RegExpPlus] (\P{Digit}|7)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 540| [RegExpConstant, RegExpNormalChar] Y +# 540| [RegExpGroup] (\P{Digit}|7) +#-----| 0 -> [RegExpAlt] \P{Digit}|7 + +# 540| [RegExpPlus] (\P{Digit}|7)+ +#-----| 0 -> [RegExpGroup] (\P{Digit}|7) # 540| [RegExpNamedCharacterProperty] \P{Digit} @@ -5755,13 +5751,9 @@ redos_variants.swift: # 540| [RegExpAlt] |7 -# 544| [RegExpGroup] (\p{IsDigit}|7) -#-----| 0 -> [RegExpAlt] \p{IsDigit}|7 +# 540| [RegExpConstant, RegExpNormalChar] 7 -# 544| [RegExpStar] (\p{IsDigit}|7)* -#-----| 0 -> [RegExpGroup] (\p{IsDigit}|7) - -# 544| [RegExpConstant, RegExpNormalChar] 7 +# 540| [RegExpConstant, RegExpNormalChar] Y # 544| [RegExpConstant, RegExpNormalChar] X @@ -5770,7 +5762,11 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\p{IsDigit}|7)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 544| [RegExpConstant, RegExpNormalChar] Y +# 544| [RegExpGroup] (\p{IsDigit}|7) +#-----| 0 -> [RegExpAlt] \p{IsDigit}|7 + +# 544| [RegExpStar] (\p{IsDigit}|7)* +#-----| 0 -> [RegExpGroup] (\p{IsDigit}|7) # 544| [RegExpNamedCharacterProperty] \p{IsDigit} @@ -5780,11 +5776,9 @@ redos_variants.swift: # 544| [RegExpAlt] |7 -# 547| [RegExpGroup] (\p{IsDigit}|b) -#-----| 0 -> [RegExpAlt] \p{IsDigit}|b +# 544| [RegExpConstant, RegExpNormalChar] 7 -# 547| [RegExpPlus] (\p{IsDigit}|b)+ -#-----| 0 -> [RegExpGroup] (\p{IsDigit}|b) +# 544| [RegExpConstant, RegExpNormalChar] Y # 547| [RegExpConstant, RegExpNormalChar] X @@ -5793,7 +5787,11 @@ redos_variants.swift: #-----| 1 -> [RegExpPlus] (\p{IsDigit}|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 547| [RegExpConstant, RegExpNormalChar] Y +# 547| [RegExpGroup] (\p{IsDigit}|b) +#-----| 0 -> [RegExpAlt] \p{IsDigit}|b + +# 547| [RegExpPlus] (\p{IsDigit}|b)+ +#-----| 0 -> [RegExpGroup] (\p{IsDigit}|b) # 547| [RegExpNamedCharacterProperty] \p{IsDigit} @@ -5801,15 +5799,11 @@ redos_variants.swift: #-----| 0 -> [RegExpNamedCharacterProperty] \p{IsDigit} #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 547| [RegExpConstant, RegExpNormalChar] b - # 547| [RegExpAlt] |b -# 551| [RegExpGroup] (\p{Alpha}|a) -#-----| 0 -> [RegExpAlt] \p{Alpha}|a +# 547| [RegExpConstant, RegExpNormalChar] b -# 551| [RegExpStar] (\p{Alpha}|a)* -#-----| 0 -> [RegExpGroup] (\p{Alpha}|a) +# 547| [RegExpConstant, RegExpNormalChar] Y # 551| [RegExpConstant, RegExpNormalChar] X @@ -5818,7 +5812,11 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\p{Alpha}|a)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 551| [RegExpConstant, RegExpNormalChar] Y +# 551| [RegExpGroup] (\p{Alpha}|a) +#-----| 0 -> [RegExpAlt] \p{Alpha}|a + +# 551| [RegExpStar] (\p{Alpha}|a)* +#-----| 0 -> [RegExpGroup] (\p{Alpha}|a) # 551| [RegExpNamedCharacterProperty] \p{Alpha} @@ -5826,17 +5824,11 @@ redos_variants.swift: #-----| 0 -> [RegExpNamedCharacterProperty] \p{Alpha} #-----| 1 -> [RegExpConstant, RegExpNormalChar] a -# 551| [RegExpConstant, RegExpNormalChar] a - # 551| [RegExpAlt] |a -# 554| [RegExpGroup] (\p{Alpha}|7) -#-----| 0 -> [RegExpAlt] \p{Alpha}|7 +# 551| [RegExpConstant, RegExpNormalChar] a -# 554| [RegExpPlus] (\p{Alpha}|7)+ -#-----| 0 -> [RegExpGroup] (\p{Alpha}|7) - -# 554| [RegExpConstant, RegExpNormalChar] 7 +# 551| [RegExpConstant, RegExpNormalChar] Y # 554| [RegExpConstant, RegExpNormalChar] X @@ -5845,7 +5837,11 @@ redos_variants.swift: #-----| 1 -> [RegExpPlus] (\p{Alpha}|7)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 554| [RegExpConstant, RegExpNormalChar] Y +# 554| [RegExpGroup] (\p{Alpha}|7) +#-----| 0 -> [RegExpAlt] \p{Alpha}|7 + +# 554| [RegExpPlus] (\p{Alpha}|7)+ +#-----| 0 -> [RegExpGroup] (\p{Alpha}|7) # 554| [RegExpNamedCharacterProperty] \p{Alpha} @@ -5855,11 +5851,19 @@ redos_variants.swift: # 554| [RegExpAlt] |7 -# 557| [RegExpConstant, RegExpNormalChar] " +# 554| [RegExpConstant, RegExpNormalChar] 7 -# 557| [RegExpConstant, RegExpNormalChar] " +# 554| [RegExpConstant, RegExpNormalChar] Y -# 557| [RegExpConstant, RegExpNormalChar] " +# 557| [RegExpGroup] ("[^"]*?"|[^"\s]+) +#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ + +# 557| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) + +# 557| [RegExpSequence] ("[^"]*?"|[^"\s]+)+(?=\s*|\s*$) +#-----| 0 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 1 -> [RegExpPositiveLookahead] (?=\s*|\s*$) # 557| [RegExpConstant, RegExpNormalChar] " @@ -5872,19 +5876,15 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] "[^"]*?" #-----| 1 -> [RegExpPlus] [^"\s]+ -# 557| [RegExpDollar] $ +# 557| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " -# 557| [RegExpGroup] ("[^"]*?"|[^"\s]+) -#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ +# 557| [RegExpStar] [^"]*? +#-----| 0 -> [RegExpCharacterClass] [^"] -# 557| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ -#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) +# 557| [RegExpConstant, RegExpNormalChar] " -# 557| [RegExpSequence] ("[^"]*?"|[^"\s]+)+(?=\s*|\s*$) -#-----| 0 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ -#-----| 1 -> [RegExpPositiveLookahead] (?=\s*|\s*$) - -# 557| [RegExpPositiveLookahead] (?=\s*|\s*$) +# 557| [RegExpConstant, RegExpNormalChar] " # 557| [RegExpCharacterClass] [^"\s] #-----| 0 -> [RegExpConstant, RegExpNormalChar] " @@ -5893,21 +5893,23 @@ redos_variants.swift: # 557| [RegExpPlus] [^"\s]+ #-----| 0 -> [RegExpCharacterClass] [^"\s] -# 557| [RegExpCharacterClass] [^"] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " - -# 557| [RegExpStar] [^"]*? -#-----| 0 -> [RegExpCharacterClass] [^"] +# 557| [RegExpConstant, RegExpNormalChar] " # 557| [RegExpCharacterClassEscape] \s -# 557| [RegExpCharacterClassEscape] \s +# 557| [RegExpPositiveLookahead] (?=\s*|\s*$) # 557| [RegExpCharacterClassEscape] \s # 557| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s +# 557| [RegExpAlt] \s*|\s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpSequence] \s*$ + +# 557| [RegExpCharacterClassEscape] \s + # 557| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s @@ -5915,15 +5917,17 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] \s* #-----| 1 -> [RegExpDollar] $ -# 557| [RegExpAlt] \s*|\s*$ -#-----| 0 -> [RegExpStar] \s* -#-----| 1 -> [RegExpSequence] \s*$ +# 557| [RegExpDollar] $ -# 560| [RegExpConstant, RegExpNormalChar] " +# 560| [RegExpGroup] ("[^"]*?"|[^"\s]+) +#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ -# 560| [RegExpConstant, RegExpNormalChar] " +# 560| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) -# 560| [RegExpConstant, RegExpNormalChar] " +# 560| [RegExpSequence] ("[^"]*?"|[^"\s]+)+(?=\s*|\s*$) +#-----| 0 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 1 -> [RegExpPositiveLookahead] (?=\s*|\s*$) # 560| [RegExpConstant, RegExpNormalChar] " @@ -5936,19 +5940,15 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] "[^"]*?" #-----| 1 -> [RegExpPlus] [^"\s]+ -# 560| [RegExpDollar] $ +# 560| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " -# 560| [RegExpGroup] ("[^"]*?"|[^"\s]+) -#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ +# 560| [RegExpStar] [^"]*? +#-----| 0 -> [RegExpCharacterClass] [^"] -# 560| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ -#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) +# 560| [RegExpConstant, RegExpNormalChar] " -# 560| [RegExpSequence] ("[^"]*?"|[^"\s]+)+(?=\s*|\s*$) -#-----| 0 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ -#-----| 1 -> [RegExpPositiveLookahead] (?=\s*|\s*$) - -# 560| [RegExpPositiveLookahead] (?=\s*|\s*$) +# 560| [RegExpConstant, RegExpNormalChar] " # 560| [RegExpCharacterClass] [^"\s] #-----| 0 -> [RegExpConstant, RegExpNormalChar] " @@ -5957,21 +5957,23 @@ redos_variants.swift: # 560| [RegExpPlus] [^"\s]+ #-----| 0 -> [RegExpCharacterClass] [^"\s] -# 560| [RegExpCharacterClass] [^"] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " - -# 560| [RegExpStar] [^"]*? -#-----| 0 -> [RegExpCharacterClass] [^"] +# 560| [RegExpConstant, RegExpNormalChar] " # 560| [RegExpCharacterClassEscape] \s -# 560| [RegExpCharacterClassEscape] \s +# 560| [RegExpPositiveLookahead] (?=\s*|\s*$) # 560| [RegExpCharacterClassEscape] \s # 560| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s +# 560| [RegExpAlt] \s*|\s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpSequence] \s*$ + +# 560| [RegExpCharacterClassEscape] \s + # 560| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s @@ -5979,15 +5981,21 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] \s* #-----| 1 -> [RegExpDollar] $ -# 560| [RegExpAlt] \s*|\s*$ -#-----| 0 -> [RegExpStar] \s* -#-----| 1 -> [RegExpSequence] \s*$ +# 560| [RegExpDollar] $ -# 564| [RegExpConstant, RegExpNormalChar] " +# 564| [RegExpConstant, RegExpNormalChar] / -# 564| [RegExpConstant, RegExpNormalChar] " +# 564| [RegExpSequence] /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X +#-----| 0 -> [RegExpConstant, RegExpNormalChar] / +#-----| 1 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 2 -> [RegExpPositiveLookahead] (?=\s*|\s*$) +#-----| 3 -> [RegExpConstant, RegExpNormalChar] X -# 564| [RegExpConstant, RegExpNormalChar] " +# 564| [RegExpGroup] ("[^"]*?"|[^"\s]+) +#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ + +# 564| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) # 564| [RegExpConstant, RegExpNormalChar] " @@ -6000,25 +6008,15 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] "[^"]*?" #-----| 1 -> [RegExpPlus] [^"\s]+ -# 564| [RegExpDollar] $ +# 564| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " -# 564| [RegExpGroup] ("[^"]*?"|[^"\s]+) -#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ +# 564| [RegExpStar] [^"]*? +#-----| 0 -> [RegExpCharacterClass] [^"] -# 564| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ -#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) +# 564| [RegExpConstant, RegExpNormalChar] " -# 564| [RegExpPositiveLookahead] (?=\s*|\s*$) - -# 564| [RegExpConstant, RegExpNormalChar] / - -# 564| [RegExpSequence] /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X -#-----| 0 -> [RegExpConstant, RegExpNormalChar] / -#-----| 1 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ -#-----| 2 -> [RegExpPositiveLookahead] (?=\s*|\s*$) -#-----| 3 -> [RegExpConstant, RegExpNormalChar] X - -# 564| [RegExpConstant, RegExpNormalChar] X +# 564| [RegExpConstant, RegExpNormalChar] " # 564| [RegExpCharacterClass] [^"\s] #-----| 0 -> [RegExpConstant, RegExpNormalChar] " @@ -6027,21 +6025,23 @@ redos_variants.swift: # 564| [RegExpPlus] [^"\s]+ #-----| 0 -> [RegExpCharacterClass] [^"\s] -# 564| [RegExpCharacterClass] [^"] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " - -# 564| [RegExpStar] [^"]*? -#-----| 0 -> [RegExpCharacterClass] [^"] +# 564| [RegExpConstant, RegExpNormalChar] " # 564| [RegExpCharacterClassEscape] \s -# 564| [RegExpCharacterClassEscape] \s +# 564| [RegExpPositiveLookahead] (?=\s*|\s*$) # 564| [RegExpCharacterClassEscape] \s # 564| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s +# 564| [RegExpAlt] \s*|\s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpSequence] \s*$ + +# 564| [RegExpCharacterClassEscape] \s + # 564| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s @@ -6049,15 +6049,22 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] \s* #-----| 1 -> [RegExpDollar] $ -# 564| [RegExpAlt] \s*|\s*$ -#-----| 0 -> [RegExpStar] \s* -#-----| 1 -> [RegExpSequence] \s*$ +# 564| [RegExpDollar] $ -# 565| [RegExpConstant, RegExpNormalChar] " +# 564| [RegExpConstant, RegExpNormalChar] X -# 565| [RegExpConstant, RegExpNormalChar] " +# 565| [RegExpConstant, RegExpNormalChar] / -# 565| [RegExpConstant, RegExpNormalChar] " +# 565| [RegExpSequence] /("[^"]*?"|[^"\s]+)+(?=X) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] / +#-----| 1 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 2 -> [RegExpPositiveLookahead] (?=X) + +# 565| [RegExpGroup] ("[^"]*?"|[^"\s]+) +#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ + +# 565| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) # 565| [RegExpConstant, RegExpNormalChar] " @@ -6070,22 +6077,15 @@ redos_variants.swift: #-----| 0 -> [RegExpSequence] "[^"]*?" #-----| 1 -> [RegExpPlus] [^"\s]+ -# 565| [RegExpGroup] ("[^"]*?"|[^"\s]+) -#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ +# 565| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " -# 565| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ -#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) +# 565| [RegExpStar] [^"]*? +#-----| 0 -> [RegExpCharacterClass] [^"] -# 565| [RegExpPositiveLookahead] (?=X) +# 565| [RegExpConstant, RegExpNormalChar] " -# 565| [RegExpConstant, RegExpNormalChar] / - -# 565| [RegExpSequence] /("[^"]*?"|[^"\s]+)+(?=X) -#-----| 0 -> [RegExpConstant, RegExpNormalChar] / -#-----| 1 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ -#-----| 2 -> [RegExpPositiveLookahead] (?=X) - -# 565| [RegExpConstant, RegExpNormalChar] X +# 565| [RegExpConstant, RegExpNormalChar] " # 565| [RegExpCharacterClass] [^"\s] #-----| 0 -> [RegExpConstant, RegExpNormalChar] " @@ -6094,21 +6094,13 @@ redos_variants.swift: # 565| [RegExpPlus] [^"\s]+ #-----| 0 -> [RegExpCharacterClass] [^"\s] -# 565| [RegExpCharacterClass] [^"] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " - -# 565| [RegExpStar] [^"]*? -#-----| 0 -> [RegExpCharacterClass] [^"] +# 565| [RegExpConstant, RegExpNormalChar] " # 565| [RegExpCharacterClassEscape] \s -# 569| [RegExpGroup] (\d|0) -#-----| 0 -> [RegExpAlt] \d|0 +# 565| [RegExpPositiveLookahead] (?=X) -# 569| [RegExpStar] (\d|0)* -#-----| 0 -> [RegExpGroup] (\d|0) - -# 569| [RegExpConstant, RegExpNormalChar] 0 +# 565| [RegExpConstant, RegExpNormalChar] X # 569| [RegExpCaret] \A @@ -6117,12 +6109,20 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\d|0)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] x +# 569| [RegExpGroup] (\d|0) +#-----| 0 -> [RegExpAlt] \d|0 + +# 569| [RegExpStar] (\d|0)* +#-----| 0 -> [RegExpGroup] (\d|0) + # 569| [RegExpCharacterClassEscape] \d # 569| [RegExpAlt] \d|0 #-----| 0 -> [RegExpCharacterClassEscape] \d #-----| 1 -> [RegExpConstant, RegExpNormalChar] 0 +# 569| [RegExpConstant, RegExpNormalChar] 0 + # 569| [RegExpConstant, RegExpNormalChar] x # 570| [RegExpGroup] (\d|0) @@ -6135,23 +6135,15 @@ redos_variants.swift: #-----| 0 -> [RegExpStar] (\d|0)* #-----| 1 -> [RegExpDollar] \Z -# 570| [RegExpConstant, RegExpNormalChar] 0 - -# 570| [RegExpDollar] \Z - # 570| [RegExpCharacterClassEscape] \d # 570| [RegExpAlt] \d|0 #-----| 0 -> [RegExpCharacterClassEscape] \d #-----| 1 -> [RegExpConstant, RegExpNormalChar] 0 -# 571| [RegExpGroup] (\d|0) -#-----| 0 -> [RegExpAlt] \d|0 +# 570| [RegExpConstant, RegExpNormalChar] 0 -# 571| [RegExpStar] (\d|0)* -#-----| 0 -> [RegExpGroup] (\d|0) - -# 571| [RegExpConstant, RegExpNormalChar] 0 +# 570| [RegExpDollar] \Z # 571| [RegExpSpecialChar] \b @@ -6160,12 +6152,20 @@ redos_variants.swift: #-----| 1 -> [RegExpStar] (\d|0)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] x +# 571| [RegExpGroup] (\d|0) +#-----| 0 -> [RegExpAlt] \d|0 + +# 571| [RegExpStar] (\d|0)* +#-----| 0 -> [RegExpGroup] (\d|0) + # 571| [RegExpCharacterClassEscape] \d # 571| [RegExpAlt] \d|0 #-----| 0 -> [RegExpCharacterClassEscape] \d #-----| 1 -> [RegExpConstant, RegExpNormalChar] 0 +# 571| [RegExpConstant, RegExpNormalChar] 0 + # 571| [RegExpConstant, RegExpNormalChar] x # 574| [RegExpConstant, RegExpNormalChar] a @@ -6195,17 +6195,17 @@ redos_variants.swift: # 576| [RegExpConstant, RegExpNormalChar] b -# 580| [RegExpConstant, RegExpNormalChar] a - -# 580| [RegExpStar] a* -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a - # 580| [RegExpConstant, RegExpNormalChar] aa # 580| [RegExpAlt] aa|a* #-----| 0 -> [RegExpConstant, RegExpNormalChar] aa #-----| 1 -> [RegExpStar] a* +# 580| [RegExpConstant, RegExpNormalChar] a + +# 580| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + # 580| [RegExpConstant, RegExpNormalChar] b # 580| [RegExpConstant, RegExpNormalChar] c @@ -6237,8 +6237,6 @@ regex.swift: # 149| [RegExpStar] ([\w.]+)* #-----| 0 -> [RegExpGroup] ([\w.]+) -# 149| [RegExpConstant, RegExpNormalChar] . - # 149| [RegExpCharacterClass] [\w.] #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpNormalChar] . @@ -6248,6 +6246,8 @@ regex.swift: # 149| [RegExpCharacterClassEscape] \w +# 149| [RegExpConstant, RegExpNormalChar] . + # 156| [RegExpConstant, RegExpNormalChar] # 156| @@ -6263,9 +6263,6 @@ regex.swift: # 168| [RegExpConstant, RegExpNormalChar] bb -# 172| [RegExpConstant, RegExpNormalChar] -# 172| bb - # 172| [RegExpConstant, RegExpNormalChar] aa # 172| [RegExpAlt] aa| @@ -6273,3 +6270,6 @@ regex.swift: #-----| 0 -> [RegExpConstant, RegExpNormalChar] aa #-----| 1 -> [RegExpConstant, RegExpNormalChar] #-----| bb + +# 172| [RegExpConstant, RegExpNormalChar] +# 172| bb From 925477ed66994167591cc15a38577b69cbe923cb Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 21 Jun 2023 18:29:10 +0100 Subject: [PATCH 258/364] Swift: Remove another bit of code that doesn't currently make sense in Swift. --- swift/ql/lib/codeql/swift/regex/RegexTreeView.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll index 2cbd1bb0d52..5c5425e071e 100644 --- a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll +++ b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll @@ -1189,7 +1189,7 @@ private module Impl implements RegexTreeViewSig { * Holds if the regular expression should not be considered. */ predicate isExcluded(RegExpParent parent) { - none() //parent.(RegExpTerm).getRegExp().(Ast::RegExpLiteral).hasFreeSpacingFlag() // exclude free-spacing mode regexes + none() } /** From bfd0a19d85ba8389cbd7728507d4e547b9e982e7 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Wed, 21 Jun 2023 18:36:39 +0100 Subject: [PATCH 259/364] Kotlin: Define DiagnosticTrapWriter, for type safety In some cases, we were writing diagnostics to TRAP files where they shouldn't be written. Such TRAP files don't define #compilation, so TRAP import gave errors. Now we use DiagnosticTrapWriter to get the type system to check that we are writing diagnostics to the right place. --- .../src/main/kotlin/ExternalDeclExtractor.kt | 6 +- .../main/kotlin/KotlinExtractorExtension.kt | 6 +- .../src/main/kotlin/KotlinUsesExtractor.kt | 4 +- .../src/main/kotlin/TrapWriter.kt | 59 +++++++++++++++---- .../src/main/kotlin/utils/Logger.kt | 54 ++++++++--------- 5 files changed, 82 insertions(+), 47 deletions(-) diff --git a/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt b/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt index c45e0a454b7..a426c7bd622 100644 --- a/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/ExternalDeclExtractor.kt @@ -14,7 +14,7 @@ import java.util.ArrayList import java.util.HashSet import java.util.zip.GZIPOutputStream -class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: String, val sourceFilePath: String, val primitiveTypeMapping: PrimitiveTypeMapping, val pluginContext: IrPluginContext, val globalExtensionState: KotlinExtractorGlobalState, val diagnosticTrapWriter: TrapWriter) { +class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: String, val sourceFilePath: String, val primitiveTypeMapping: PrimitiveTypeMapping, val pluginContext: IrPluginContext, val globalExtensionState: KotlinExtractorGlobalState, val diagnosticTrapWriter: DiagnosticTrapWriter) { val declBinaryNames = HashMap() val externalDeclsDone = HashSet>() @@ -95,8 +95,8 @@ class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: Stri val binaryPath = getIrClassBinaryPath(containingClass) // We want our comments to be the first thing in the file, - // so start off with a mere TrapWriter - val tw = TrapWriter(logger.loggerBase, TrapLabelManager(), trapFileBW, diagnosticTrapWriter) + // so start off with a PlainTrapWriter + val tw = PlainTrapWriter(logger.loggerBase, TrapLabelManager(), trapFileBW, diagnosticTrapWriter) tw.writeComment("Generated by the CodeQL Kotlin extractor for external dependencies") tw.writeComment("Part of invocation $invocationTrapFile") if (signature != possiblyLongSignature) { diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinExtractorExtension.kt b/java/kotlin-extractor/src/main/kotlin/KotlinExtractorExtension.kt index 9bfcabd20fb..c766d70df33 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinExtractorExtension.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinExtractorExtension.kt @@ -127,7 +127,7 @@ class KotlinExtractorExtension( val lm = TrapLabelManager() val logCounter = LogCounter() val loggerBase = LoggerBase(logCounter) - val tw = TrapWriter(loggerBase, lm, invocationTrapFileBW, null) + val tw = DiagnosticTrapWriter(loggerBase, lm, invocationTrapFileBW) // The interceptor has already defined #compilation = * val compilation: Label = StringLabel("compilation") tw.writeCompilation_started(compilation) @@ -324,13 +324,13 @@ private fun doFile( trapFileWriter.getTempWriter().use { trapFileBW -> // We want our comments to be the first thing in the file, // so start off with a mere TrapWriter - val tw = TrapWriter(loggerBase, TrapLabelManager(), trapFileBW, fileTrapWriter) + val tw = PlainTrapWriter(loggerBase, TrapLabelManager(), trapFileBW, fileTrapWriter.getDiagnosticTrapWriter()) tw.writeComment("Generated by the CodeQL Kotlin extractor for kotlin source code") tw.writeComment("Part of invocation $invocationTrapFile") // Now elevate to a SourceFileTrapWriter, and populate the // file information val sftw = tw.makeSourceFileTrapWriter(srcFile, true) - val externalDeclExtractor = ExternalDeclExtractor(logger, invocationTrapFile, srcFilePath, primitiveTypeMapping, pluginContext, globalExtensionState, fileTrapWriter) + val externalDeclExtractor = ExternalDeclExtractor(logger, invocationTrapFile, srcFilePath, primitiveTypeMapping, pluginContext, globalExtensionState, fileTrapWriter.getDiagnosticTrapWriter()) val linesOfCode = LinesOfCode(logger, sftw, srcFile) val fileExtractor = KotlinFileExtractor(logger, sftw, linesOfCode, srcFilePath, null, externalDeclExtractor, primitiveTypeMapping, pluginContext, KotlinFileExtractor.DeclarationStack(), globalExtensionState) diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index 9c552233158..fdaebe5f1c8 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -139,13 +139,13 @@ open class KotlinUsesExtractor( if (clsFile == null || isExternalDeclaration(cls)) { val filePath = getIrClassBinaryPath(cls) val newTrapWriter = tw.makeFileTrapWriter(filePath, true) - val newLoggerTrapWriter = logger.tw.makeFileTrapWriter(filePath, false) + val newLoggerTrapWriter = logger.dtw.makeFileTrapWriter(filePath, false) val newLogger = FileLogger(logger.loggerBase, newLoggerTrapWriter) return KotlinFileExtractor(newLogger, newTrapWriter, null, filePath, dependencyCollector, externalClassExtractor, primitiveTypeMapping, pluginContext, newDeclarationStack, globalExtensionState) } val newTrapWriter = tw.makeSourceFileTrapWriter(clsFile, true) - val newLoggerTrapWriter = logger.tw.makeSourceFileTrapWriter(clsFile, false) + val newLoggerTrapWriter = logger.dtw.makeSourceFileTrapWriter(clsFile, false) val newLogger = FileLogger(logger.loggerBase, newLoggerTrapWriter) return KotlinFileExtractor(newLogger, newTrapWriter, null, clsFile.path, dependencyCollector, externalClassExtractor, primitiveTypeMapping, pluginContext, newDeclarationStack, globalExtensionState) } diff --git a/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt b/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt index eb9feeb4559..b27aec9cc52 100644 --- a/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt +++ b/java/kotlin-extractor/src/main/kotlin/TrapWriter.kt @@ -57,7 +57,9 @@ class TrapLabelManager { * share the same `TrapLabelManager` and `BufferedWriter`. */ // TODO lm was `protected` before anonymousTypeMapping and locallyVisibleFunctionLabelMapping moved into it. Should we re-protect it and provide accessors? -open class TrapWriter (protected val loggerBase: LoggerBase, val lm: TrapLabelManager, private val bw: BufferedWriter, val diagnosticTrapWriter: TrapWriter?) { +abstract class TrapWriter (protected val loggerBase: LoggerBase, val lm: TrapLabelManager, private val bw: BufferedWriter) { + abstract fun getDiagnosticTrapWriter(): DiagnosticTrapWriter + /** * Returns the label that is defined to be the given key, if such * a label exists, and `null` otherwise. Most users will want to use @@ -223,7 +225,7 @@ open class TrapWriter (protected val loggerBase: LoggerBase, val lm: TrapLabelMa val len = str.length val newLen = UTF8Util.encodablePrefixLength(str, MAX_STRLEN) if (newLen < len) { - loggerBase.warn(diagnosticTrapWriter ?: this, + loggerBase.warn(this.getDiagnosticTrapWriter(), "Truncated string of length $len", "Truncated string of length $len, starting '${str.take(100)}', ending '${str.takeLast(100)}'") return str.take(newLen) @@ -237,14 +239,43 @@ open class TrapWriter (protected val loggerBase: LoggerBase, val lm: TrapLabelMa * writer etc), but using the given `filePath` for locations. */ fun makeFileTrapWriter(filePath: String, populateFileTables: Boolean) = - FileTrapWriter(loggerBase, lm, bw, diagnosticTrapWriter, filePath, populateFileTables) + FileTrapWriter(loggerBase, lm, bw, this.getDiagnosticTrapWriter(), filePath, populateFileTables) /** * Gets a FileTrapWriter like this one (using the same label manager, * writer etc), but using the given `IrFile` for locations. */ fun makeSourceFileTrapWriter(file: IrFile, populateFileTables: Boolean) = - SourceFileTrapWriter(loggerBase, lm, bw, diagnosticTrapWriter, file, populateFileTables) + SourceFileTrapWriter(loggerBase, lm, bw, this.getDiagnosticTrapWriter(), file, populateFileTables) +} + +/** + * A `PlainTrapWriter` has no additional context of its own. + */ +class PlainTrapWriter ( + loggerBase: LoggerBase, + lm: TrapLabelManager, + bw: BufferedWriter, + val dtw: DiagnosticTrapWriter +): TrapWriter (loggerBase, lm, bw) { + override fun getDiagnosticTrapWriter(): DiagnosticTrapWriter { + return dtw + } +} + +/** + * A `DiagnosticTrapWriter` is a TrapWriter that diagnostics can be + * written to; i.e. it has the #compilation label defined. In practice, + * this means that it is a TrapWriter for the invocation TRAP file. + */ +class DiagnosticTrapWriter ( + loggerBase: LoggerBase, + lm: TrapLabelManager, + bw: BufferedWriter +): TrapWriter (loggerBase, lm, bw) { + override fun getDiagnosticTrapWriter(): DiagnosticTrapWriter { + return this + } } /** @@ -259,16 +290,20 @@ open class FileTrapWriter ( loggerBase: LoggerBase, lm: TrapLabelManager, bw: BufferedWriter, - diagnosticTrapWriter: TrapWriter?, + val dtw: DiagnosticTrapWriter, val filePath: String, populateFileTables: Boolean -): TrapWriter (loggerBase, lm, bw, diagnosticTrapWriter) { +): TrapWriter (loggerBase, lm, bw) { /** * The ID for the file that we are extracting from. */ val fileId = mkFileId(filePath, populateFileTables) + override fun getDiagnosticTrapWriter(): DiagnosticTrapWriter { + return dtw + } + private fun offsetMinOf(default: Int, vararg options: Int?): Int { if (default == UNDEFINED_OFFSET || default == SYNTHETIC_OFFSET) { return default @@ -349,10 +384,10 @@ class SourceFileTrapWriter ( loggerBase: LoggerBase, lm: TrapLabelManager, bw: BufferedWriter, - diagnosticTrapWriter: TrapWriter?, + dtw: DiagnosticTrapWriter, val irFile: IrFile, populateFileTables: Boolean) : - FileTrapWriter(loggerBase, lm, bw, diagnosticTrapWriter, irFile.path, populateFileTables) { + FileTrapWriter(loggerBase, lm, bw, dtw, irFile.path, populateFileTables) { /** * The file entry for the file that we are extracting from. @@ -363,14 +398,14 @@ class SourceFileTrapWriter ( override fun getLocation(startOffset: Int, endOffset: Int): Label { if (startOffset == UNDEFINED_OFFSET || endOffset == UNDEFINED_OFFSET) { if (startOffset != endOffset) { - loggerBase.warn(this, "Location with inconsistent offsets (start $startOffset, end $endOffset)", null) + loggerBase.warn(dtw, "Location with inconsistent offsets (start $startOffset, end $endOffset)", null) } return getWholeFileLocation() } if (startOffset == SYNTHETIC_OFFSET || endOffset == SYNTHETIC_OFFSET) { if (startOffset != endOffset) { - loggerBase.warn(this, "Location with inconsistent offsets (start $startOffset, end $endOffset)", null) + loggerBase.warn(dtw, "Location with inconsistent offsets (start $startOffset, end $endOffset)", null) } return getWholeFileLocation() } @@ -390,14 +425,14 @@ class SourceFileTrapWriter ( override fun getLocationString(e: IrElement): String { if (e.startOffset == UNDEFINED_OFFSET || e.endOffset == UNDEFINED_OFFSET) { if (e.startOffset != e.endOffset) { - loggerBase.warn(this, "Location with inconsistent offsets (start ${e.startOffset}, end ${e.endOffset})", null) + loggerBase.warn(dtw, "Location with inconsistent offsets (start ${e.startOffset}, end ${e.endOffset})", null) } return "" } if (e.startOffset == SYNTHETIC_OFFSET || e.endOffset == SYNTHETIC_OFFSET) { if (e.startOffset != e.endOffset) { - loggerBase.warn(this, "Location with inconsistent offsets (start ${e.startOffset}, end ${e.endOffset})", null) + loggerBase.warn(dtw, "Location with inconsistent offsets (start ${e.startOffset}, end ${e.endOffset})", null) } return "" } diff --git a/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt b/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt index 3b66e527429..6c9e6f5d64d 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt @@ -107,7 +107,7 @@ open class LoggerBase(val logCounter: LogCounter) { file_number_diagnostic_number = 0 } - fun diagnostic(tw: TrapWriter, severity: Severity, msg: String, extraInfo: String?, locationString: String? = null, mkLocationId: () -> Label = { tw.unknownLocation }) { + fun diagnostic(dtw: DiagnosticTrapWriter, severity: Severity, msg: String, extraInfo: String?, locationString: String? = null, mkLocationId: () -> Label = { dtw.unknownLocation }) { val diagnosticLoc = getDiagnosticLocation() val diagnosticLocStr = if(diagnosticLoc == null) "" else diagnosticLoc val suffix = @@ -121,7 +121,7 @@ open class LoggerBase(val logCounter: LogCounter) { // counting machinery if (verbosity >= 1) { val message = "Severity mismatch ($severity vs ${oldInfo.first}) at $diagnosticLoc" - emitDiagnostic(tw, Severity.Error, "Inconsistency", message, message) + emitDiagnostic(dtw, Severity.Error, "Inconsistency", message, message) } } val newCount = oldInfo.second + 1 @@ -149,18 +149,18 @@ open class LoggerBase(val logCounter: LogCounter) { fullMsgBuilder.append(suffix) val fullMsg = fullMsgBuilder.toString() - emitDiagnostic(tw, severity, diagnosticLocStr, msg, fullMsg, locationString, mkLocationId) + emitDiagnostic(dtw, severity, diagnosticLocStr, msg, fullMsg, locationString, mkLocationId) } - private fun emitDiagnostic(tw: TrapWriter, severity: Severity, diagnosticLocStr: String, msg: String, fullMsg: String, locationString: String? = null, mkLocationId: () -> Label = { tw.unknownLocation }) { + private fun emitDiagnostic(dtw: DiagnosticTrapWriter, severity: Severity, diagnosticLocStr: String, msg: String, fullMsg: String, locationString: String? = null, mkLocationId: () -> Label = { dtw.unknownLocation }) { val locStr = if (locationString == null) "" else "At " + locationString + ": " val kind = if (severity <= Severity.WarnHigh) "WARN" else "ERROR" val logMessage = LogMessage(kind, "Diagnostic($diagnosticLocStr): $locStr$fullMsg") // We don't actually make the location until after the `return` above val locationId = mkLocationId() - val diagLabel = tw.getFreshIdLabel() - tw.writeDiagnostics(diagLabel, "CodeQL Kotlin extractor", severity.sev, "", msg, "${logMessage.timestamp} $fullMsg", locationId) - tw.writeDiagnostic_for(diagLabel, StringLabel("compilation"), file_number, file_number_diagnostic_number++) + val diagLabel = dtw.getFreshIdLabel() + dtw.writeDiagnostics(diagLabel, "CodeQL Kotlin extractor", severity.sev, "", msg, "${logMessage.timestamp} $fullMsg", locationId) + dtw.writeDiagnostic_for(diagLabel, StringLabel("compilation"), file_number, file_number_diagnostic_number++) logStream.write(logMessage.toJsonLine()) } @@ -188,18 +188,18 @@ open class LoggerBase(val logCounter: LogCounter) { } } - fun warn(tw: TrapWriter, msg: String, extraInfo: String?) { + fun warn(dtw: DiagnosticTrapWriter, msg: String, extraInfo: String?) { if (verbosity >= 2) { - diagnostic(tw, Severity.Warn, msg, extraInfo) + diagnostic(dtw, Severity.Warn, msg, extraInfo) } } - fun error(tw: TrapWriter, msg: String, extraInfo: String?) { + fun error(dtw: DiagnosticTrapWriter, msg: String, extraInfo: String?) { if (verbosity >= 1) { - diagnostic(tw, Severity.Error, msg, extraInfo) + diagnostic(dtw, Severity.Error, msg, extraInfo) } } - fun printLimitedDiagnosticCounts(tw: TrapWriter) { + fun printLimitedDiagnosticCounts(dtw: DiagnosticTrapWriter) { for((caller, info) in logCounter.diagnosticInfo) { val severity = info.first val count = info.second @@ -209,7 +209,7 @@ open class LoggerBase(val logCounter: LogCounter) { // to be an error regardless. val message = "Total of $count diagnostics (reached limit of ${logCounter.diagnosticLimit}) from $caller." if (verbosity >= 1) { - emitDiagnostic(tw, severity, "Limit", message, message) + emitDiagnostic(dtw, severity, "Limit", message, message) } } } @@ -224,28 +224,28 @@ open class LoggerBase(val logCounter: LogCounter) { } } -open class Logger(val loggerBase: LoggerBase, open val tw: TrapWriter) { +open class Logger(val loggerBase: LoggerBase, open val dtw: DiagnosticTrapWriter) { fun flush() { - tw.flush() + dtw.flush() loggerBase.flush() } fun trace(msg: String) { - loggerBase.trace(tw, msg) + loggerBase.trace(dtw, msg) } fun trace(msg: String, exn: Throwable) { trace(msg + "\n" + exn.stackTraceToString()) } fun debug(msg: String) { - loggerBase.debug(tw, msg) + loggerBase.debug(dtw, msg) } fun info(msg: String) { - loggerBase.info(tw, msg) + loggerBase.info(dtw, msg) } private fun warn(msg: String, extraInfo: String?) { - loggerBase.warn(tw, msg, extraInfo) + loggerBase.warn(dtw, msg, extraInfo) } fun warn(msg: String, exn: Throwable) { warn(msg, exn.stackTraceToString()) @@ -255,7 +255,7 @@ open class Logger(val loggerBase: LoggerBase, open val tw: TrapWriter) { } private fun error(msg: String, extraInfo: String?) { - loggerBase.error(tw, msg, extraInfo) + loggerBase.error(dtw, msg, extraInfo) } fun error(msg: String) { error(msg, null) @@ -265,16 +265,16 @@ open class Logger(val loggerBase: LoggerBase, open val tw: TrapWriter) { } } -class FileLogger(loggerBase: LoggerBase, override val tw: FileTrapWriter): Logger(loggerBase, tw) { +class FileLogger(loggerBase: LoggerBase, val ftw: FileTrapWriter): Logger(loggerBase, ftw.getDiagnosticTrapWriter()) { fun warnElement(msg: String, element: IrElement, exn: Throwable? = null) { - val locationString = tw.getLocationString(element) - val mkLocationId = { tw.getLocation(element) } - loggerBase.diagnostic(tw, Severity.Warn, msg, exn?.stackTraceToString(), locationString, mkLocationId) + val locationString = ftw.getLocationString(element) + val mkLocationId = { ftw.getLocation(element) } + loggerBase.diagnostic(ftw.getDiagnosticTrapWriter(), Severity.Warn, msg, exn?.stackTraceToString(), locationString, mkLocationId) } fun errorElement(msg: String, element: IrElement, exn: Throwable? = null) { - val locationString = tw.getLocationString(element) - val mkLocationId = { tw.getLocation(element) } - loggerBase.diagnostic(tw, Severity.Error, msg, exn?.stackTraceToString(), locationString, mkLocationId) + val locationString = ftw.getLocationString(element) + val mkLocationId = { ftw.getLocation(element) } + loggerBase.diagnostic(ftw.getDiagnosticTrapWriter(), Severity.Error, msg, exn?.stackTraceToString(), locationString, mkLocationId) } } From d3af8c5123ea34d7050d9cae6feec4e058f5cf2c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 21 Jun 2023 18:45:38 +0100 Subject: [PATCH 260/364] Swift: The perf. issue is fixed by above commit "Do regex locations more like Ruby does them." --- .../lib/codeql/swift/regex/RegexTreeView.qll | 4 +- .../test/library-tests/regex/parse.expected | 1792 +++++++++-------- .../library-tests/regex/redos_variants.swift | 13 +- 3 files changed, 957 insertions(+), 852 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll index 5c5425e071e..beaff7a4129 100644 --- a/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll +++ b/swift/ql/lib/codeql/swift/regex/RegexTreeView.qll @@ -1188,9 +1188,7 @@ private module Impl implements RegexTreeViewSig { /** * Holds if the regular expression should not be considered. */ - predicate isExcluded(RegExpParent parent) { - none() - } + predicate isExcluded(RegExpParent parent) { none() } /** * Holds if `term` is a possessive quantifier. diff --git a/swift/ql/test/library-tests/regex/parse.expected b/swift/ql/test/library-tests/regex/parse.expected index dc846fffdc8..007337ca05b 100644 --- a/swift/ql/test/library-tests/regex/parse.expected +++ b/swift/ql/test/library-tests/regex/parse.expected @@ -3986,32 +3986,140 @@ redos_variants.swift: # 379| [RegExpConstant, RegExpEscape] \] -# 392| [RegExpConstant, RegExpNormalChar] a +# 382| [RegExpGroup] (\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*) +#-----| 0 -> [RegExpSequence] \w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w* -# 392| [RegExpRange] a{2,3} +# 382| [RegExpPlus] (\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+ +#-----| 0 -> [RegExpGroup] (\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*) + +# 382| [RegExpSequence] (\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+- +#-----| 0 -> [RegExpPlus] (\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+ +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + +# 382| [RegExpCharacterClassEscape] \w + +# 382| [RegExpStar] \w* +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 382| [RegExpSequence] \w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w* +#-----| 0 -> [RegExpStar] \w* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] foobarbaz +#-----| 2 -> [RegExpStar] \w* +#-----| 3 -> [RegExpConstant, RegExpNormalChar] foobarbaz +#-----| 4 -> [RegExpStar] \w* +#-----| 5 -> [RegExpConstant, RegExpNormalChar] foobarbaz +#-----| 6 -> [RegExpStar] \w* +#-----| 7 -> [RegExpConstant, RegExpNormalChar] foobarbaz +#-----| 8 -> [RegExpStar] \s* +#-----| 9 -> [RegExpConstant, RegExpNormalChar] foobarbaz +#-----| 10 -> [RegExpStar] \d* +#-----| 11 -> [RegExpConstant, RegExpNormalChar] foobarbaz +#-----| 12 -> [RegExpStar] \w* + +# 382| [RegExpConstant, RegExpNormalChar] foobarbaz + +# 382| [RegExpCharacterClassEscape] \w + +# 382| [RegExpStar] \w* +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 382| [RegExpConstant, RegExpNormalChar] foobarbaz + +# 382| [RegExpCharacterClassEscape] \w + +# 382| [RegExpStar] \w* +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 382| [RegExpConstant, RegExpNormalChar] foobarbaz + +# 382| [RegExpCharacterClassEscape] \w + +# 382| [RegExpStar] \w* +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 382| [RegExpConstant, RegExpNormalChar] foobarbaz + +# 382| [RegExpCharacterClassEscape] \s + +# 382| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 382| [RegExpConstant, RegExpNormalChar] foobarbaz + +# 382| [RegExpCharacterClassEscape] \d + +# 382| [RegExpStar] \d* +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 382| [RegExpConstant, RegExpNormalChar] foobarbaz + +# 382| [RegExpCharacterClassEscape] \w + +# 382| [RegExpStar] \w* +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 382| [RegExpConstant, RegExpNormalChar] - + +# 386| [RegExpGroup] (\w*foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar) +#-----| 0 -> [RegExpSequence] \w*foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar + +# 386| [RegExpPlus] (\w*foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar)+ +#-----| 0 -> [RegExpGroup] (\w*foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar) + +# 386| [RegExpCharacterClassEscape] \w + +# 386| [RegExpStar] \w* +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 386| [RegExpSequence] \w*foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar +#-----| 0 -> [RegExpStar] \w* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar + +# 386| [RegExpConstant, RegExpNormalChar] foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar + +# 387| [RegExpGroup] (\w*foobarfoobarfoobar) +#-----| 0 -> [RegExpSequence] \w*foobarfoobarfoobar + +# 387| [RegExpPlus] (\w*foobarfoobarfoobar)+ +#-----| 0 -> [RegExpGroup] (\w*foobarfoobarfoobar) + +# 387| [RegExpCharacterClassEscape] \w + +# 387| [RegExpStar] \w* +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 387| [RegExpSequence] \w*foobarfoobarfoobar +#-----| 0 -> [RegExpStar] \w* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] foobarfoobarfoobar + +# 387| [RegExpConstant, RegExpNormalChar] foobarfoobarfoobar + +# 391| [RegExpConstant, RegExpNormalChar] a + +# 391| [RegExpRange] a{2,3} #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 392| [RegExpSequence] a{2,3}(b+)+X +# 391| [RegExpSequence] a{2,3}(b+)+X #-----| 0 -> [RegExpRange] a{2,3} #-----| 1 -> [RegExpPlus] (b+)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] X -# 392| [RegExpGroup] (b+) +# 391| [RegExpGroup] (b+) #-----| 0 -> [RegExpPlus] b+ -# 392| [RegExpPlus] (b+)+ +# 391| [RegExpPlus] (b+)+ #-----| 0 -> [RegExpGroup] (b+) -# 392| [RegExpConstant, RegExpNormalChar] b +# 391| [RegExpConstant, RegExpNormalChar] b -# 392| [RegExpPlus] b+ +# 391| [RegExpPlus] b+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] b -# 392| [RegExpConstant, RegExpNormalChar] X +# 391| [RegExpConstant, RegExpNormalChar] X -# 396| [RegExpCaret] ^ +# 395| [RegExpCaret] ^ -# 396| [RegExpSequence] ^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)> +# 395| [RegExpSequence] ^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)> #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpConstant, RegExpNormalChar] < #-----| 2 -> [RegExpGroup] (\w+) @@ -4020,390 +4128,390 @@ redos_variants.swift: #-----| 5 -> [RegExpGroup] (\/?) #-----| 6 -> [RegExpConstant, RegExpNormalChar] > -# 396| [RegExpConstant, RegExpNormalChar] < +# 395| [RegExpConstant, RegExpNormalChar] < -# 396| [RegExpGroup] (\w+) +# 395| [RegExpGroup] (\w+) #-----| 0 -> [RegExpPlus] \w+ -# 396| [RegExpCharacterClassEscape] \w +# 395| [RegExpCharacterClassEscape] \w -# 396| [RegExpPlus] \w+ +# 395| [RegExpPlus] \w+ #-----| 0 -> [RegExpCharacterClassEscape] \w -# 396| [RegExpGroup] ((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*) +# 395| [RegExpGroup] ((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*) #-----| 0 -> [RegExpStar] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)* -# 396| [RegExpGroup] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?) +# 395| [RegExpGroup] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?) #-----| 0 -> [RegExpSequence] \s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? -# 396| [RegExpStar] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)* +# 395| [RegExpStar] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)* #-----| 0 -> [RegExpGroup] (?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?) -# 396| [RegExpCharacterClassEscape] \s +# 395| [RegExpCharacterClassEscape] \s -# 396| [RegExpPlus] \s+ +# 395| [RegExpPlus] \s+ #-----| 0 -> [RegExpCharacterClassEscape] \s -# 396| [RegExpSequence] \s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? +# 395| [RegExpSequence] \s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? #-----| 0 -> [RegExpPlus] \s+ #-----| 1 -> [RegExpPlus] \w+ #-----| 2 -> [RegExpOpt] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? -# 396| [RegExpCharacterClassEscape] \w +# 395| [RegExpCharacterClassEscape] \w -# 396| [RegExpPlus] \w+ +# 395| [RegExpPlus] \w+ #-----| 0 -> [RegExpCharacterClassEscape] \w -# 396| [RegExpGroup] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+)) +# 395| [RegExpGroup] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+)) #-----| 0 -> [RegExpSequence] \s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) -# 396| [RegExpOpt] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? +# 395| [RegExpOpt] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))? #-----| 0 -> [RegExpGroup] (?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+)) -# 396| [RegExpCharacterClassEscape] \s +# 395| [RegExpCharacterClassEscape] \s -# 396| [RegExpStar] \s* +# 395| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s -# 396| [RegExpSequence] \s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) +# 395| [RegExpSequence] \s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) #-----| 0 -> [RegExpStar] \s* #-----| 1 -> [RegExpConstant, RegExpNormalChar] = #-----| 2 -> [RegExpStar] \s* #-----| 3 -> [RegExpGroup] (?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) -# 396| [RegExpConstant, RegExpNormalChar] = +# 395| [RegExpConstant, RegExpNormalChar] = -# 396| [RegExpCharacterClassEscape] \s +# 395| [RegExpCharacterClassEscape] \s -# 396| [RegExpStar] \s* +# 395| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s -# 396| [RegExpGroup] (?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) +# 395| [RegExpGroup] (?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+) #-----| 0 -> [RegExpAlt] (?:"[^"]*")|(?:'[^']*')|[^>\s]+ -# 396| [RegExpGroup] (?:"[^"]*") +# 395| [RegExpGroup] (?:"[^"]*") #-----| 0 -> [RegExpSequence] "[^"]*" -# 396| [RegExpAlt] (?:"[^"]*")|(?:'[^']*')|[^>\s]+ +# 395| [RegExpAlt] (?:"[^"]*")|(?:'[^']*')|[^>\s]+ #-----| 0 -> [RegExpGroup] (?:"[^"]*") #-----| 1 -> [RegExpGroup] (?:'[^']*') #-----| 2 -> [RegExpPlus] [^>\s]+ -# 396| [RegExpConstant, RegExpNormalChar] " +# 395| [RegExpConstant, RegExpNormalChar] " -# 396| [RegExpSequence] "[^"]*" +# 395| [RegExpSequence] "[^"]*" #-----| 0 -> [RegExpConstant, RegExpNormalChar] " #-----| 1 -> [RegExpStar] [^"]* #-----| 2 -> [RegExpConstant, RegExpNormalChar] " -# 396| [RegExpCharacterClass] [^"] +# 395| [RegExpCharacterClass] [^"] #-----| 0 -> [RegExpConstant, RegExpNormalChar] " -# 396| [RegExpStar] [^"]* +# 395| [RegExpStar] [^"]* #-----| 0 -> [RegExpCharacterClass] [^"] -# 396| [RegExpConstant, RegExpNormalChar] " +# 395| [RegExpConstant, RegExpNormalChar] " -# 396| [RegExpConstant, RegExpNormalChar] " +# 395| [RegExpConstant, RegExpNormalChar] " -# 396| [RegExpGroup] (?:'[^']*') +# 395| [RegExpGroup] (?:'[^']*') #-----| 0 -> [RegExpSequence] '[^']*' -# 396| [RegExpConstant, RegExpNormalChar] ' +# 395| [RegExpConstant, RegExpNormalChar] ' -# 396| [RegExpSequence] '[^']*' +# 395| [RegExpSequence] '[^']*' #-----| 0 -> [RegExpConstant, RegExpNormalChar] ' #-----| 1 -> [RegExpStar] [^']* #-----| 2 -> [RegExpConstant, RegExpNormalChar] ' -# 396| [RegExpCharacterClass] [^'] +# 395| [RegExpCharacterClass] [^'] #-----| 0 -> [RegExpConstant, RegExpNormalChar] ' -# 396| [RegExpStar] [^']* +# 395| [RegExpStar] [^']* #-----| 0 -> [RegExpCharacterClass] [^'] -# 396| [RegExpConstant, RegExpNormalChar] ' +# 395| [RegExpConstant, RegExpNormalChar] ' -# 396| [RegExpConstant, RegExpNormalChar] ' +# 395| [RegExpConstant, RegExpNormalChar] ' -# 396| [RegExpCharacterClass] [^>\s] +# 395| [RegExpCharacterClass] [^>\s] #-----| 0 -> [RegExpConstant, RegExpNormalChar] > #-----| 1 -> [RegExpCharacterClassEscape] \s -# 396| [RegExpPlus] [^>\s]+ +# 395| [RegExpPlus] [^>\s]+ #-----| 0 -> [RegExpCharacterClass] [^>\s] -# 396| [RegExpConstant, RegExpNormalChar] > +# 395| [RegExpConstant, RegExpNormalChar] > -# 396| [RegExpCharacterClassEscape] \s +# 395| [RegExpCharacterClassEscape] \s -# 396| [RegExpCharacterClassEscape] \s +# 395| [RegExpCharacterClassEscape] \s -# 396| [RegExpStar] \s* +# 395| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s -# 396| [RegExpGroup] (\/?) +# 395| [RegExpGroup] (\/?) #-----| 0 -> [RegExpOpt] \/? -# 396| [RegExpConstant, RegExpEscape] \/ +# 395| [RegExpConstant, RegExpEscape] \/ -# 396| [RegExpOpt] \/? +# 395| [RegExpOpt] \/? #-----| 0 -> [RegExpConstant, RegExpEscape] \/ -# 396| [RegExpConstant, RegExpNormalChar] > +# 395| [RegExpConstant, RegExpNormalChar] > -# 399| [RegExpGroup] (a+) +# 398| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ -# 399| [RegExpStar] (a+)* +# 398| [RegExpStar] (a+)* #-----| 0 -> [RegExpGroup] (a+) -# 399| [RegExpSequence] (a+)*[\s\S][\s\S][\s\S]? +# 398| [RegExpSequence] (a+)*[\s\S][\s\S][\s\S]? #-----| 0 -> [RegExpStar] (a+)* #-----| 1 -> [RegExpCharacterClass] [\s\S] #-----| 2 -> [RegExpCharacterClass] [\s\S] #-----| 3 -> [RegExpOpt] [\s\S]? -# 399| [RegExpConstant, RegExpNormalChar] a +# 398| [RegExpConstant, RegExpNormalChar] a -# 399| [RegExpPlus] a+ +# 398| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 399| [RegExpCharacterClass] [\s\S] +# 398| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S -# 399| [RegExpCharacterClassEscape] \s +# 398| [RegExpCharacterClassEscape] \s -# 399| [RegExpCharacterClassEscape] \S +# 398| [RegExpCharacterClassEscape] \S -# 399| [RegExpCharacterClass] [\s\S] +# 398| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S -# 399| [RegExpCharacterClassEscape] \s +# 398| [RegExpCharacterClassEscape] \s -# 399| [RegExpCharacterClassEscape] \S +# 398| [RegExpCharacterClassEscape] \S -# 399| [RegExpCharacterClass] [\s\S] +# 398| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S -# 399| [RegExpOpt] [\s\S]? +# 398| [RegExpOpt] [\s\S]? #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 399| [RegExpCharacterClassEscape] \s +# 398| [RegExpCharacterClassEscape] \s -# 399| [RegExpCharacterClassEscape] \S +# 398| [RegExpCharacterClassEscape] \S -# 402| [RegExpGroup] (a+) +# 401| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ -# 402| [RegExpStar] (a+)* +# 401| [RegExpStar] (a+)* #-----| 0 -> [RegExpGroup] (a+) -# 402| [RegExpSequence] (a+)*[\s\S]{2,3} +# 401| [RegExpSequence] (a+)*[\s\S]{2,3} #-----| 0 -> [RegExpStar] (a+)* #-----| 1 -> [RegExpRange] [\s\S]{2,3} -# 402| [RegExpConstant, RegExpNormalChar] a +# 401| [RegExpConstant, RegExpNormalChar] a -# 402| [RegExpPlus] a+ +# 401| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 402| [RegExpCharacterClass] [\s\S] +# 401| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S -# 402| [RegExpRange] [\s\S]{2,3} +# 401| [RegExpRange] [\s\S]{2,3} #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 402| [RegExpCharacterClassEscape] \s +# 401| [RegExpCharacterClassEscape] \s -# 402| [RegExpCharacterClassEscape] \S +# 401| [RegExpCharacterClassEscape] \S -# 405| [RegExpGroup] (a+) +# 404| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ -# 405| [RegExpStar] (a+)* +# 404| [RegExpStar] (a+)* #-----| 0 -> [RegExpGroup] (a+) -# 405| [RegExpSequence] (a+)*([\s\S]{2,}|X)$ +# 404| [RegExpSequence] (a+)*([\s\S]{2,}|X)$ #-----| 0 -> [RegExpStar] (a+)* #-----| 1 -> [RegExpGroup] ([\s\S]{2,}|X) #-----| 2 -> [RegExpDollar] $ -# 405| [RegExpConstant, RegExpNormalChar] a +# 404| [RegExpConstant, RegExpNormalChar] a -# 405| [RegExpPlus] a+ +# 404| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 405| [RegExpGroup] ([\s\S]{2,}|X) +# 404| [RegExpGroup] ([\s\S]{2,}|X) #-----| 0 -> [RegExpAlt] [\s\S]{2,}|X -# 405| [RegExpCharacterClass] [\s\S] +# 404| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S -# 405| [InfiniteRepetitionQuantifier, RegExpRange] [\s\S]{2,} +# 404| [InfiniteRepetitionQuantifier, RegExpRange] [\s\S]{2,} #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 405| [RegExpAlt] [\s\S]{2,}|X +# 404| [RegExpAlt] [\s\S]{2,}|X #-----| 0 -> [InfiniteRepetitionQuantifier, RegExpRange] [\s\S]{2,} #-----| 1 -> [RegExpConstant, RegExpNormalChar] X -# 405| [RegExpCharacterClassEscape] \s +# 404| [RegExpCharacterClassEscape] \s -# 405| [RegExpCharacterClassEscape] \S +# 404| [RegExpCharacterClassEscape] \S -# 405| [RegExpConstant, RegExpNormalChar] X +# 404| [RegExpConstant, RegExpNormalChar] X -# 405| [RegExpDollar] $ +# 404| [RegExpDollar] $ -# 408| [RegExpGroup] (a+) +# 407| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ -# 408| [RegExpStar] (a+)* +# 407| [RegExpStar] (a+)* #-----| 0 -> [RegExpGroup] (a+) -# 408| [RegExpSequence] (a+)*([\s\S]*|X)$ +# 407| [RegExpSequence] (a+)*([\s\S]*|X)$ #-----| 0 -> [RegExpStar] (a+)* #-----| 1 -> [RegExpGroup] ([\s\S]*|X) #-----| 2 -> [RegExpDollar] $ -# 408| [RegExpConstant, RegExpNormalChar] a +# 407| [RegExpConstant, RegExpNormalChar] a -# 408| [RegExpPlus] a+ +# 407| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 408| [RegExpGroup] ([\s\S]*|X) +# 407| [RegExpGroup] ([\s\S]*|X) #-----| 0 -> [RegExpAlt] [\s\S]*|X -# 408| [RegExpCharacterClass] [\s\S] +# 407| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S -# 408| [RegExpStar] [\s\S]* +# 407| [RegExpStar] [\s\S]* #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 408| [RegExpAlt] [\s\S]*|X +# 407| [RegExpAlt] [\s\S]*|X #-----| 0 -> [RegExpStar] [\s\S]* #-----| 1 -> [RegExpConstant, RegExpNormalChar] X -# 408| [RegExpCharacterClassEscape] \s +# 407| [RegExpCharacterClassEscape] \s -# 408| [RegExpCharacterClassEscape] \S +# 407| [RegExpCharacterClassEscape] \S -# 408| [RegExpConstant, RegExpNormalChar] X +# 407| [RegExpConstant, RegExpNormalChar] X -# 408| [RegExpDollar] $ +# 407| [RegExpDollar] $ -# 412| [RegExpGroup] ((a+)*$|[\s\S]+) +# 411| [RegExpGroup] ((a+)*$|[\s\S]+) #-----| 0 -> [RegExpAlt] (a+)*$|[\s\S]+ -# 412| [RegExpGroup] (a+) +# 411| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ -# 412| [RegExpStar] (a+)* +# 411| [RegExpStar] (a+)* #-----| 0 -> [RegExpGroup] (a+) -# 412| [RegExpSequence] (a+)*$ +# 411| [RegExpSequence] (a+)*$ #-----| 0 -> [RegExpStar] (a+)* #-----| 1 -> [RegExpDollar] $ -# 412| [RegExpAlt] (a+)*$|[\s\S]+ +# 411| [RegExpAlt] (a+)*$|[\s\S]+ #-----| 0 -> [RegExpSequence] (a+)*$ #-----| 1 -> [RegExpPlus] [\s\S]+ -# 412| [RegExpConstant, RegExpNormalChar] a +# 411| [RegExpConstant, RegExpNormalChar] a -# 412| [RegExpPlus] a+ +# 411| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 412| [RegExpDollar] $ +# 411| [RegExpDollar] $ -# 412| [RegExpCharacterClass] [\s\S] +# 411| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S -# 412| [RegExpPlus] [\s\S]+ +# 411| [RegExpPlus] [\s\S]+ #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 412| [RegExpCharacterClassEscape] \s +# 411| [RegExpCharacterClassEscape] \s -# 412| [RegExpCharacterClassEscape] \S +# 411| [RegExpCharacterClassEscape] \S -# 415| [RegExpGroup] ([\s\S]+|(a+)*$) +# 414| [RegExpGroup] ([\s\S]+|(a+)*$) #-----| 0 -> [RegExpAlt] [\s\S]+|(a+)*$ -# 415| [RegExpCharacterClass] [\s\S] +# 414| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S -# 415| [RegExpPlus] [\s\S]+ +# 414| [RegExpPlus] [\s\S]+ #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 415| [RegExpAlt] [\s\S]+|(a+)*$ +# 414| [RegExpAlt] [\s\S]+|(a+)*$ #-----| 0 -> [RegExpPlus] [\s\S]+ #-----| 1 -> [RegExpSequence] (a+)*$ -# 415| [RegExpCharacterClassEscape] \s +# 414| [RegExpCharacterClassEscape] \s -# 415| [RegExpCharacterClassEscape] \S +# 414| [RegExpCharacterClassEscape] \S -# 415| [RegExpGroup] (a+) +# 414| [RegExpGroup] (a+) #-----| 0 -> [RegExpPlus] a+ -# 415| [RegExpStar] (a+)* +# 414| [RegExpStar] (a+)* #-----| 0 -> [RegExpGroup] (a+) -# 415| [RegExpSequence] (a+)*$ +# 414| [RegExpSequence] (a+)*$ #-----| 0 -> [RegExpStar] (a+)* #-----| 1 -> [RegExpDollar] $ -# 415| [RegExpConstant, RegExpNormalChar] a +# 414| [RegExpConstant, RegExpNormalChar] a -# 415| [RegExpPlus] a+ +# 414| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 415| [RegExpDollar] $ +# 414| [RegExpDollar] $ -# 418| [RegExpGroup] ((;|^)a+) +# 417| [RegExpGroup] ((;|^)a+) #-----| 0 -> [RegExpSequence] (;|^)a+ -# 418| [RegExpPlus] ((;|^)a+)+ +# 417| [RegExpPlus] ((;|^)a+)+ #-----| 0 -> [RegExpGroup] ((;|^)a+) -# 418| [RegExpSequence] ((;|^)a+)+$ +# 417| [RegExpSequence] ((;|^)a+)+$ #-----| 0 -> [RegExpPlus] ((;|^)a+)+ #-----| 1 -> [RegExpDollar] $ -# 418| [RegExpGroup] (;|^) +# 417| [RegExpGroup] (;|^) #-----| 0 -> [RegExpAlt] ;|^ -# 418| [RegExpSequence] (;|^)a+ +# 417| [RegExpSequence] (;|^)a+ #-----| 0 -> [RegExpGroup] (;|^) #-----| 1 -> [RegExpPlus] a+ -# 418| [RegExpConstant, RegExpNormalChar] ; +# 417| [RegExpConstant, RegExpNormalChar] ; -# 418| [RegExpAlt] ;|^ +# 417| [RegExpAlt] ;|^ #-----| 0 -> [RegExpConstant, RegExpNormalChar] ; #-----| 1 -> [RegExpCaret] ^ -# 418| [RegExpCaret] ^ +# 417| [RegExpCaret] ^ -# 418| [RegExpConstant, RegExpNormalChar] a +# 417| [RegExpConstant, RegExpNormalChar] a -# 418| [RegExpPlus] a+ +# 417| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 418| [RegExpDollar] $ +# 417| [RegExpDollar] $ -# 422| [RegExpGroup] (^|;) +# 421| [RegExpGroup] (^|;) #-----| 0 -> [RegExpAlt] ^|; -# 422| [RegExpSequence] (^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f +# 421| [RegExpSequence] (^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f #-----| 0 -> [RegExpGroup] (^|;) #-----| 1 -> [RegExpGroup] (0|1) #-----| 2 -> [RegExpGroup] (0|1) @@ -4422,736 +4530,736 @@ redos_variants.swift: #-----| 15 -> [RegExpPlus] (e+)+ #-----| 16 -> [RegExpConstant, RegExpNormalChar] f -# 422| [RegExpCaret] ^ +# 421| [RegExpCaret] ^ -# 422| [RegExpAlt] ^|; +# 421| [RegExpAlt] ^|; #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpConstant, RegExpNormalChar] ; -# 422| [RegExpConstant, RegExpNormalChar] ; +# 421| [RegExpConstant, RegExpNormalChar] ; -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (0|1) +# 421| [RegExpGroup] (0|1) #-----| 0 -> [RegExpAlt] 0|1 -# 422| [RegExpConstant, RegExpNormalChar] 0 +# 421| [RegExpConstant, RegExpNormalChar] 0 -# 422| [RegExpAlt] 0|1 +# 421| [RegExpAlt] 0|1 #-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 #-----| 1 -> [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpConstant, RegExpNormalChar] 1 +# 421| [RegExpConstant, RegExpNormalChar] 1 -# 422| [RegExpGroup] (e+) +# 421| [RegExpGroup] (e+) #-----| 0 -> [RegExpPlus] e+ -# 422| [RegExpPlus] (e+)+ +# 421| [RegExpPlus] (e+)+ #-----| 0 -> [RegExpGroup] (e+) -# 422| [RegExpConstant, RegExpNormalChar] e +# 421| [RegExpConstant, RegExpNormalChar] e -# 422| [RegExpPlus] e+ +# 421| [RegExpPlus] e+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] e -# 422| [RegExpConstant, RegExpNormalChar] f +# 421| [RegExpConstant, RegExpNormalChar] f -# 426| [RegExpCaret] ^ +# 425| [RegExpCaret] ^ -# 426| [RegExpSequence] ^ab(c+)+$ +# 425| [RegExpSequence] ^ab(c+)+$ #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpConstant, RegExpNormalChar] ab #-----| 2 -> [RegExpPlus] (c+)+ #-----| 3 -> [RegExpDollar] $ -# 426| [RegExpConstant, RegExpNormalChar] ab +# 425| [RegExpConstant, RegExpNormalChar] ab -# 426| [RegExpGroup] (c+) +# 425| [RegExpGroup] (c+) #-----| 0 -> [RegExpPlus] c+ -# 426| [RegExpPlus] (c+)+ +# 425| [RegExpPlus] (c+)+ #-----| 0 -> [RegExpGroup] (c+) -# 426| [RegExpConstant, RegExpNormalChar] c +# 425| [RegExpConstant, RegExpNormalChar] c -# 426| [RegExpPlus] c+ +# 425| [RegExpPlus] c+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] c -# 426| [RegExpDollar] $ +# 425| [RegExpDollar] $ -# 430| [RegExpGroup] (\d(\s+)*) +# 429| [RegExpGroup] (\d(\s+)*) #-----| 0 -> [RegExpSequence] \d(\s+)* -# 430| [RegExpRange] (\d(\s+)*){20} +# 429| [RegExpRange] (\d(\s+)*){20} #-----| 0 -> [RegExpGroup] (\d(\s+)*) -# 430| [RegExpCharacterClassEscape] \d +# 429| [RegExpCharacterClassEscape] \d -# 430| [RegExpSequence] \d(\s+)* +# 429| [RegExpSequence] \d(\s+)* #-----| 0 -> [RegExpCharacterClassEscape] \d #-----| 1 -> [RegExpStar] (\s+)* -# 430| [RegExpGroup] (\s+) +# 429| [RegExpGroup] (\s+) #-----| 0 -> [RegExpPlus] \s+ -# 430| [RegExpStar] (\s+)* +# 429| [RegExpStar] (\s+)* #-----| 0 -> [RegExpGroup] (\s+) -# 430| [RegExpCharacterClassEscape] \s +# 429| [RegExpCharacterClassEscape] \s -# 430| [RegExpPlus] \s+ +# 429| [RegExpPlus] \s+ #-----| 0 -> [RegExpCharacterClassEscape] \s -# 433| [RegExpGroup] (([^/]|X)+) +# 432| [RegExpGroup] (([^/]|X)+) #-----| 0 -> [RegExpPlus] ([^/]|X)+ -# 433| [RegExpSequence] (([^/]|X)+)(\/[\s\S]*)*$ +# 432| [RegExpSequence] (([^/]|X)+)(\/[\s\S]*)*$ #-----| 0 -> [RegExpGroup] (([^/]|X)+) #-----| 1 -> [RegExpStar] (\/[\s\S]*)* #-----| 2 -> [RegExpDollar] $ -# 433| [RegExpGroup] ([^/]|X) +# 432| [RegExpGroup] ([^/]|X) #-----| 0 -> [RegExpAlt] [^/]|X -# 433| [RegExpPlus] ([^/]|X)+ +# 432| [RegExpPlus] ([^/]|X)+ #-----| 0 -> [RegExpGroup] ([^/]|X) -# 433| [RegExpCharacterClass] [^/] +# 432| [RegExpCharacterClass] [^/] #-----| 0 -> [RegExpConstant, RegExpNormalChar] / -# 433| [RegExpAlt] [^/]|X +# 432| [RegExpAlt] [^/]|X #-----| 0 -> [RegExpCharacterClass] [^/] #-----| 1 -> [RegExpConstant, RegExpNormalChar] X -# 433| [RegExpConstant, RegExpNormalChar] / +# 432| [RegExpConstant, RegExpNormalChar] / -# 433| [RegExpConstant, RegExpNormalChar] X +# 432| [RegExpConstant, RegExpNormalChar] X -# 433| [RegExpGroup] (\/[\s\S]*) +# 432| [RegExpGroup] (\/[\s\S]*) #-----| 0 -> [RegExpSequence] \/[\s\S]* -# 433| [RegExpStar] (\/[\s\S]*)* +# 432| [RegExpStar] (\/[\s\S]*)* #-----| 0 -> [RegExpGroup] (\/[\s\S]*) -# 433| [RegExpConstant, RegExpEscape] \/ +# 432| [RegExpConstant, RegExpEscape] \/ -# 433| [RegExpSequence] \/[\s\S]* +# 432| [RegExpSequence] \/[\s\S]* #-----| 0 -> [RegExpConstant, RegExpEscape] \/ #-----| 1 -> [RegExpStar] [\s\S]* -# 433| [RegExpCharacterClass] [\s\S] +# 432| [RegExpCharacterClass] [\s\S] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpCharacterClassEscape] \S -# 433| [RegExpStar] [\s\S]* +# 432| [RegExpStar] [\s\S]* #-----| 0 -> [RegExpCharacterClass] [\s\S] -# 433| [RegExpCharacterClassEscape] \s +# 432| [RegExpCharacterClassEscape] \s -# 433| [RegExpCharacterClassEscape] \S +# 432| [RegExpCharacterClassEscape] \S -# 433| [RegExpDollar] $ +# 432| [RegExpDollar] $ -# 436| [RegExpCaret] ^ +# 435| [RegExpCaret] ^ -# 436| [RegExpSequence] ^((x([^Y]+)?)*(Y|$)) +# 435| [RegExpSequence] ^((x([^Y]+)?)*(Y|$)) #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpGroup] ((x([^Y]+)?)*(Y|$)) -# 436| [RegExpGroup] ((x([^Y]+)?)*(Y|$)) +# 435| [RegExpGroup] ((x([^Y]+)?)*(Y|$)) #-----| 0 -> [RegExpSequence] (x([^Y]+)?)*(Y|$) -# 436| [RegExpGroup] (x([^Y]+)?) +# 435| [RegExpGroup] (x([^Y]+)?) #-----| 0 -> [RegExpSequence] x([^Y]+)? -# 436| [RegExpStar] (x([^Y]+)?)* +# 435| [RegExpStar] (x([^Y]+)?)* #-----| 0 -> [RegExpGroup] (x([^Y]+)?) -# 436| [RegExpSequence] (x([^Y]+)?)*(Y|$) +# 435| [RegExpSequence] (x([^Y]+)?)*(Y|$) #-----| 0 -> [RegExpStar] (x([^Y]+)?)* #-----| 1 -> [RegExpGroup] (Y|$) -# 436| [RegExpConstant, RegExpNormalChar] x +# 435| [RegExpConstant, RegExpNormalChar] x -# 436| [RegExpSequence] x([^Y]+)? +# 435| [RegExpSequence] x([^Y]+)? #-----| 0 -> [RegExpConstant, RegExpNormalChar] x #-----| 1 -> [RegExpOpt] ([^Y]+)? -# 436| [RegExpGroup] ([^Y]+) +# 435| [RegExpGroup] ([^Y]+) #-----| 0 -> [RegExpPlus] [^Y]+ -# 436| [RegExpOpt] ([^Y]+)? +# 435| [RegExpOpt] ([^Y]+)? #-----| 0 -> [RegExpGroup] ([^Y]+) -# 436| [RegExpCharacterClass] [^Y] +# 435| [RegExpCharacterClass] [^Y] #-----| 0 -> [RegExpConstant, RegExpNormalChar] Y -# 436| [RegExpPlus] [^Y]+ +# 435| [RegExpPlus] [^Y]+ #-----| 0 -> [RegExpCharacterClass] [^Y] -# 436| [RegExpConstant, RegExpNormalChar] Y +# 435| [RegExpConstant, RegExpNormalChar] Y -# 436| [RegExpGroup] (Y|$) +# 435| [RegExpGroup] (Y|$) #-----| 0 -> [RegExpAlt] Y|$ -# 436| [RegExpConstant, RegExpNormalChar] Y +# 435| [RegExpConstant, RegExpNormalChar] Y -# 436| [RegExpAlt] Y|$ +# 435| [RegExpAlt] Y|$ #-----| 0 -> [RegExpConstant, RegExpNormalChar] Y #-----| 1 -> [RegExpDollar] $ -# 436| [RegExpDollar] $ +# 435| [RegExpDollar] $ -# 440| [RegExpConstant, RegExpNormalChar] foo +# 439| [RegExpConstant, RegExpNormalChar] foo -# 440| [RegExpSequence] foo([\w-]*)+bar +# 439| [RegExpSequence] foo([\w-]*)+bar #-----| 0 -> [RegExpConstant, RegExpNormalChar] foo #-----| 1 -> [RegExpPlus] ([\w-]*)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] bar -# 440| [RegExpGroup] ([\w-]*) +# 439| [RegExpGroup] ([\w-]*) #-----| 0 -> [RegExpStar] [\w-]* -# 440| [RegExpPlus] ([\w-]*)+ +# 439| [RegExpPlus] ([\w-]*)+ #-----| 0 -> [RegExpGroup] ([\w-]*) -# 440| [RegExpCharacterClass] [\w-] +# 439| [RegExpCharacterClass] [\w-] #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpNormalChar] - -# 440| [RegExpStar] [\w-]* +# 439| [RegExpStar] [\w-]* #-----| 0 -> [RegExpCharacterClass] [\w-] -# 440| [RegExpCharacterClassEscape] \w +# 439| [RegExpCharacterClassEscape] \w -# 440| [RegExpConstant, RegExpNormalChar] - +# 439| [RegExpConstant, RegExpNormalChar] - -# 440| [RegExpConstant, RegExpNormalChar] bar +# 439| [RegExpConstant, RegExpNormalChar] bar -# 444| [RegExpGroup] ((ab)*) +# 443| [RegExpGroup] ((ab)*) #-----| 0 -> [RegExpStar] (ab)* -# 444| [RegExpPlus] ((ab)*)+ +# 443| [RegExpPlus] ((ab)*)+ #-----| 0 -> [RegExpGroup] ((ab)*) -# 444| [RegExpSequence] ((ab)*)+c +# 443| [RegExpSequence] ((ab)*)+c #-----| 0 -> [RegExpPlus] ((ab)*)+ #-----| 1 -> [RegExpConstant, RegExpNormalChar] c -# 444| [RegExpGroup] (ab) +# 443| [RegExpGroup] (ab) #-----| 0 -> [RegExpConstant, RegExpNormalChar] ab -# 444| [RegExpStar] (ab)* +# 443| [RegExpStar] (ab)* #-----| 0 -> [RegExpGroup] (ab) -# 444| [RegExpConstant, RegExpNormalChar] ab +# 443| [RegExpConstant, RegExpNormalChar] ab -# 444| [RegExpConstant, RegExpNormalChar] c +# 443| [RegExpConstant, RegExpNormalChar] c -# 448| [RegExpGroup] (a?a?) +# 447| [RegExpGroup] (a?a?) #-----| 0 -> [RegExpSequence] a?a? -# 448| [RegExpStar] (a?a?)* +# 447| [RegExpStar] (a?a?)* #-----| 0 -> [RegExpGroup] (a?a?) -# 448| [RegExpSequence] (a?a?)*b +# 447| [RegExpSequence] (a?a?)*b #-----| 0 -> [RegExpStar] (a?a?)* #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 448| [RegExpConstant, RegExpNormalChar] a +# 447| [RegExpConstant, RegExpNormalChar] a -# 448| [RegExpOpt] a? +# 447| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 448| [RegExpSequence] a?a? +# 447| [RegExpSequence] a?a? #-----| 0 -> [RegExpOpt] a? #-----| 1 -> [RegExpOpt] a? -# 448| [RegExpConstant, RegExpNormalChar] a +# 447| [RegExpConstant, RegExpNormalChar] a -# 448| [RegExpOpt] a? +# 447| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 448| [RegExpConstant, RegExpNormalChar] b +# 447| [RegExpConstant, RegExpNormalChar] b -# 451| [RegExpGroup] (a?) +# 450| [RegExpGroup] (a?) #-----| 0 -> [RegExpOpt] a? -# 451| [RegExpStar] (a?)* +# 450| [RegExpStar] (a?)* #-----| 0 -> [RegExpGroup] (a?) -# 451| [RegExpSequence] (a?)*b +# 450| [RegExpSequence] (a?)*b #-----| 0 -> [RegExpStar] (a?)* #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 451| [RegExpConstant, RegExpNormalChar] a +# 450| [RegExpConstant, RegExpNormalChar] a -# 451| [RegExpOpt] a? +# 450| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 451| [RegExpConstant, RegExpNormalChar] b +# 450| [RegExpConstant, RegExpNormalChar] b -# 455| [RegExpGroup] (c?a?) +# 454| [RegExpGroup] (c?a?) #-----| 0 -> [RegExpSequence] c?a? -# 455| [RegExpStar] (c?a?)* +# 454| [RegExpStar] (c?a?)* #-----| 0 -> [RegExpGroup] (c?a?) -# 455| [RegExpSequence] (c?a?)*b +# 454| [RegExpSequence] (c?a?)*b #-----| 0 -> [RegExpStar] (c?a?)* #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 455| [RegExpConstant, RegExpNormalChar] c +# 454| [RegExpConstant, RegExpNormalChar] c -# 455| [RegExpOpt] c? +# 454| [RegExpOpt] c? #-----| 0 -> [RegExpConstant, RegExpNormalChar] c -# 455| [RegExpSequence] c?a? +# 454| [RegExpSequence] c?a? #-----| 0 -> [RegExpOpt] c? #-----| 1 -> [RegExpOpt] a? -# 455| [RegExpConstant, RegExpNormalChar] a +# 454| [RegExpConstant, RegExpNormalChar] a -# 455| [RegExpOpt] a? +# 454| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 455| [RegExpConstant, RegExpNormalChar] b +# 454| [RegExpConstant, RegExpNormalChar] b -# 459| [RegExpGroup] (?:a|a?) +# 458| [RegExpGroup] (?:a|a?) #-----| 0 -> [RegExpAlt] a|a? -# 459| [RegExpPlus] (?:a|a?)+ +# 458| [RegExpPlus] (?:a|a?)+ #-----| 0 -> [RegExpGroup] (?:a|a?) -# 459| [RegExpSequence] (?:a|a?)+b +# 458| [RegExpSequence] (?:a|a?)+b #-----| 0 -> [RegExpPlus] (?:a|a?)+ #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 459| [RegExpConstant, RegExpNormalChar] a +# 458| [RegExpConstant, RegExpNormalChar] a -# 459| [RegExpAlt] a|a? +# 458| [RegExpAlt] a|a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpOpt] a? -# 459| [RegExpConstant, RegExpNormalChar] a +# 458| [RegExpConstant, RegExpNormalChar] a -# 459| [RegExpOpt] a? +# 458| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 459| [RegExpConstant, RegExpNormalChar] b +# 458| [RegExpConstant, RegExpNormalChar] b -# 463| [RegExpGroup] (a?b?) +# 462| [RegExpGroup] (a?b?) #-----| 0 -> [RegExpSequence] a?b? -# 463| [RegExpStar] (a?b?)* +# 462| [RegExpStar] (a?b?)* #-----| 0 -> [RegExpGroup] (a?b?) -# 463| [RegExpSequence] (a?b?)*$ +# 462| [RegExpSequence] (a?b?)*$ #-----| 0 -> [RegExpStar] (a?b?)* #-----| 1 -> [RegExpDollar] $ -# 463| [RegExpConstant, RegExpNormalChar] a +# 462| [RegExpConstant, RegExpNormalChar] a -# 463| [RegExpOpt] a? +# 462| [RegExpOpt] a? #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 463| [RegExpSequence] a?b? +# 462| [RegExpSequence] a?b? #-----| 0 -> [RegExpOpt] a? #-----| 1 -> [RegExpOpt] b? -# 463| [RegExpConstant, RegExpNormalChar] b +# 462| [RegExpConstant, RegExpNormalChar] b -# 463| [RegExpOpt] b? +# 462| [RegExpOpt] b? #-----| 0 -> [RegExpConstant, RegExpNormalChar] b -# 463| [RegExpDollar] $ +# 462| [RegExpDollar] $ -# 467| [RegExpConstant, RegExpNormalChar] PRE +# 466| [RegExpConstant, RegExpNormalChar] PRE -# 467| [RegExpSequence] PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$) +# 466| [RegExpSequence] PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$) #-----| 0 -> [RegExpConstant, RegExpNormalChar] PRE #-----| 1 -> [RegExpPlus] (([a-c]|[c-d])T(e?e?e?e?|X))+ #-----| 2 -> [RegExpGroup] (cTcT|cTXcTX$) -# 467| [RegExpGroup] (([a-c]|[c-d])T(e?e?e?e?|X)) +# 466| [RegExpGroup] (([a-c]|[c-d])T(e?e?e?e?|X)) #-----| 0 -> [RegExpSequence] ([a-c]|[c-d])T(e?e?e?e?|X) -# 467| [RegExpPlus] (([a-c]|[c-d])T(e?e?e?e?|X))+ +# 466| [RegExpPlus] (([a-c]|[c-d])T(e?e?e?e?|X))+ #-----| 0 -> [RegExpGroup] (([a-c]|[c-d])T(e?e?e?e?|X)) -# 467| [RegExpGroup] ([a-c]|[c-d]) +# 466| [RegExpGroup] ([a-c]|[c-d]) #-----| 0 -> [RegExpAlt] [a-c]|[c-d] -# 467| [RegExpSequence] ([a-c]|[c-d])T(e?e?e?e?|X) +# 466| [RegExpSequence] ([a-c]|[c-d])T(e?e?e?e?|X) #-----| 0 -> [RegExpGroup] ([a-c]|[c-d]) #-----| 1 -> [RegExpConstant, RegExpNormalChar] T #-----| 2 -> [RegExpGroup] (e?e?e?e?|X) -# 467| [RegExpCharacterClass] [a-c] +# 466| [RegExpCharacterClass] [a-c] #-----| 0 -> [RegExpCharacterRange] a-c -# 467| [RegExpAlt] [a-c]|[c-d] +# 466| [RegExpAlt] [a-c]|[c-d] #-----| 0 -> [RegExpCharacterClass] [a-c] #-----| 1 -> [RegExpCharacterClass] [c-d] -# 467| [RegExpConstant, RegExpNormalChar] a +# 466| [RegExpConstant, RegExpNormalChar] a -# 467| [RegExpCharacterRange] a-c +# 466| [RegExpCharacterRange] a-c #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpConstant, RegExpNormalChar] c -# 467| [RegExpConstant, RegExpNormalChar] c +# 466| [RegExpConstant, RegExpNormalChar] c -# 467| [RegExpCharacterClass] [c-d] +# 466| [RegExpCharacterClass] [c-d] #-----| 0 -> [RegExpCharacterRange] c-d -# 467| [RegExpConstant, RegExpNormalChar] c +# 466| [RegExpConstant, RegExpNormalChar] c -# 467| [RegExpCharacterRange] c-d +# 466| [RegExpCharacterRange] c-d #-----| 0 -> [RegExpConstant, RegExpNormalChar] c #-----| 1 -> [RegExpConstant, RegExpNormalChar] d -# 467| [RegExpConstant, RegExpNormalChar] d +# 466| [RegExpConstant, RegExpNormalChar] d -# 467| [RegExpConstant, RegExpNormalChar] T +# 466| [RegExpConstant, RegExpNormalChar] T -# 467| [RegExpGroup] (e?e?e?e?|X) +# 466| [RegExpGroup] (e?e?e?e?|X) #-----| 0 -> [RegExpAlt] e?e?e?e?|X -# 467| [RegExpConstant, RegExpNormalChar] e +# 466| [RegExpConstant, RegExpNormalChar] e -# 467| [RegExpOpt] e? +# 466| [RegExpOpt] e? #-----| 0 -> [RegExpConstant, RegExpNormalChar] e -# 467| [RegExpSequence] e?e?e?e? +# 466| [RegExpSequence] e?e?e?e? #-----| 0 -> [RegExpOpt] e? #-----| 1 -> [RegExpOpt] e? #-----| 2 -> [RegExpOpt] e? #-----| 3 -> [RegExpOpt] e? -# 467| [RegExpAlt] e?e?e?e?|X +# 466| [RegExpAlt] e?e?e?e?|X #-----| 0 -> [RegExpSequence] e?e?e?e? #-----| 1 -> [RegExpConstant, RegExpNormalChar] X -# 467| [RegExpConstant, RegExpNormalChar] e +# 466| [RegExpConstant, RegExpNormalChar] e -# 467| [RegExpOpt] e? +# 466| [RegExpOpt] e? #-----| 0 -> [RegExpConstant, RegExpNormalChar] e -# 467| [RegExpConstant, RegExpNormalChar] e +# 466| [RegExpConstant, RegExpNormalChar] e -# 467| [RegExpOpt] e? +# 466| [RegExpOpt] e? #-----| 0 -> [RegExpConstant, RegExpNormalChar] e -# 467| [RegExpConstant, RegExpNormalChar] e +# 466| [RegExpConstant, RegExpNormalChar] e -# 467| [RegExpOpt] e? +# 466| [RegExpOpt] e? #-----| 0 -> [RegExpConstant, RegExpNormalChar] e -# 467| [RegExpConstant, RegExpNormalChar] X +# 466| [RegExpConstant, RegExpNormalChar] X -# 467| [RegExpGroup] (cTcT|cTXcTX$) +# 466| [RegExpGroup] (cTcT|cTXcTX$) #-----| 0 -> [RegExpAlt] cTcT|cTXcTX$ -# 467| [RegExpConstant, RegExpNormalChar] cTcT +# 466| [RegExpConstant, RegExpNormalChar] cTcT -# 467| [RegExpAlt] cTcT|cTXcTX$ +# 466| [RegExpAlt] cTcT|cTXcTX$ #-----| 0 -> [RegExpConstant, RegExpNormalChar] cTcT #-----| 1 -> [RegExpSequence] cTXcTX$ -# 467| [RegExpConstant, RegExpNormalChar] cTXcTX +# 466| [RegExpConstant, RegExpNormalChar] cTXcTX -# 467| [RegExpSequence] cTXcTX$ +# 466| [RegExpSequence] cTXcTX$ #-----| 0 -> [RegExpConstant, RegExpNormalChar] cTXcTX #-----| 1 -> [RegExpDollar] $ -# 467| [RegExpDollar] $ +# 466| [RegExpDollar] $ -# 471| [RegExpCaret] ^ +# 470| [RegExpCaret] ^ -# 471| [RegExpSequence] ^((a)+\w)+$ +# 470| [RegExpSequence] ^((a)+\w)+$ #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpPlus] ((a)+\w)+ #-----| 2 -> [RegExpDollar] $ -# 471| [RegExpGroup] ((a)+\w) +# 470| [RegExpGroup] ((a)+\w) #-----| 0 -> [RegExpSequence] (a)+\w -# 471| [RegExpPlus] ((a)+\w)+ +# 470| [RegExpPlus] ((a)+\w)+ #-----| 0 -> [RegExpGroup] ((a)+\w) -# 471| [RegExpGroup] (a) +# 470| [RegExpGroup] (a) #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 471| [RegExpPlus] (a)+ +# 470| [RegExpPlus] (a)+ #-----| 0 -> [RegExpGroup] (a) -# 471| [RegExpSequence] (a)+\w +# 470| [RegExpSequence] (a)+\w #-----| 0 -> [RegExpPlus] (a)+ #-----| 1 -> [RegExpCharacterClassEscape] \w -# 471| [RegExpConstant, RegExpNormalChar] a +# 470| [RegExpConstant, RegExpNormalChar] a -# 471| [RegExpCharacterClassEscape] \w +# 470| [RegExpCharacterClassEscape] \w -# 471| [RegExpDollar] $ +# 470| [RegExpDollar] $ -# 475| [RegExpCaret] ^ +# 474| [RegExpCaret] ^ -# 475| [RegExpSequence] ^(b+.)+$ +# 474| [RegExpSequence] ^(b+.)+$ #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpPlus] (b+.)+ #-----| 2 -> [RegExpDollar] $ -# 475| [RegExpGroup] (b+.) +# 474| [RegExpGroup] (b+.) #-----| 0 -> [RegExpSequence] b+. -# 475| [RegExpPlus] (b+.)+ +# 474| [RegExpPlus] (b+.)+ #-----| 0 -> [RegExpGroup] (b+.) -# 475| [RegExpConstant, RegExpNormalChar] b +# 474| [RegExpConstant, RegExpNormalChar] b -# 475| [RegExpPlus] b+ +# 474| [RegExpPlus] b+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] b -# 475| [RegExpSequence] b+. +# 474| [RegExpSequence] b+. #-----| 0 -> [RegExpPlus] b+ #-----| 1 -> [RegExpDot] . -# 475| [RegExpDot] . +# 474| [RegExpDot] . -# 475| [RegExpDollar] $ +# 474| [RegExpDollar] $ -# 479| [RegExpGroup] (a*) +# 478| [RegExpGroup] (a*) #-----| 0 -> [RegExpStar] a* -# 479| [RegExpStar] (a*)* +# 478| [RegExpStar] (a*)* #-----| 0 -> [RegExpGroup] (a*) -# 479| [RegExpSequence] (a*)*b +# 478| [RegExpSequence] (a*)*b #-----| 0 -> [RegExpStar] (a*)* #-----| 1 -> [RegExpConstant, RegExpNormalChar] b +# 478| [RegExpConstant, RegExpNormalChar] a + +# 478| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 478| [RegExpConstant, RegExpNormalChar] b + +# 479| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 479| [RegExpStar] (a+)* +#-----| 0 -> [RegExpGroup] (a+) + +# 479| [RegExpSequence] (a+)*b +#-----| 0 -> [RegExpStar] (a+)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + # 479| [RegExpConstant, RegExpNormalChar] a -# 479| [RegExpStar] a* +# 479| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a # 479| [RegExpConstant, RegExpNormalChar] b -# 480| [RegExpGroup] (a+) -#-----| 0 -> [RegExpPlus] a+ +# 480| [RegExpGroup] (a*) +#-----| 0 -> [RegExpStar] a* -# 480| [RegExpStar] (a+)* -#-----| 0 -> [RegExpGroup] (a+) +# 480| [RegExpPlus] (a*)+ +#-----| 0 -> [RegExpGroup] (a*) -# 480| [RegExpSequence] (a+)*b -#-----| 0 -> [RegExpStar] (a+)* +# 480| [RegExpSequence] (a*)+b +#-----| 0 -> [RegExpPlus] (a*)+ #-----| 1 -> [RegExpConstant, RegExpNormalChar] b # 480| [RegExpConstant, RegExpNormalChar] a -# 480| [RegExpPlus] a+ +# 480| [RegExpStar] a* #-----| 0 -> [RegExpConstant, RegExpNormalChar] a # 480| [RegExpConstant, RegExpNormalChar] b -# 481| [RegExpGroup] (a*) -#-----| 0 -> [RegExpStar] a* +# 481| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ -# 481| [RegExpPlus] (a*)+ -#-----| 0 -> [RegExpGroup] (a*) +# 481| [RegExpPlus] (a+)+ +#-----| 0 -> [RegExpGroup] (a+) -# 481| [RegExpSequence] (a*)+b -#-----| 0 -> [RegExpPlus] (a*)+ +# 481| [RegExpSequence] (a+)+b +#-----| 0 -> [RegExpPlus] (a+)+ #-----| 1 -> [RegExpConstant, RegExpNormalChar] b # 481| [RegExpConstant, RegExpNormalChar] a -# 481| [RegExpStar] a* +# 481| [RegExpPlus] a+ #-----| 0 -> [RegExpConstant, RegExpNormalChar] a # 481| [RegExpConstant, RegExpNormalChar] b -# 482| [RegExpGroup] (a+) -#-----| 0 -> [RegExpPlus] a+ - -# 482| [RegExpPlus] (a+)+ -#-----| 0 -> [RegExpGroup] (a+) - -# 482| [RegExpSequence] (a+)+b -#-----| 0 -> [RegExpPlus] (a+)+ -#-----| 1 -> [RegExpConstant, RegExpNormalChar] b - -# 482| [RegExpConstant, RegExpNormalChar] a - -# 482| [RegExpPlus] a+ -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a - -# 482| [RegExpConstant, RegExpNormalChar] b - -# 485| [RegExpGroup] (a|b) +# 484| [RegExpGroup] (a|b) #-----| 0 -> [RegExpAlt] a|b -# 485| [RegExpPlus] (a|b)+ +# 484| [RegExpPlus] (a|b)+ #-----| 0 -> [RegExpGroup] (a|b) -# 485| [RegExpConstant, RegExpNormalChar] a +# 484| [RegExpConstant, RegExpNormalChar] a -# 485| [RegExpAlt] a|b +# 484| [RegExpAlt] a|b #-----| 0 -> [RegExpConstant, RegExpNormalChar] a #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 485| [RegExpConstant, RegExpNormalChar] b +# 484| [RegExpConstant, RegExpNormalChar] b -# 488| [RegExpGroup] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\])) +# 487| [RegExpGroup] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\])) #-----| 0 -> [RegExpAlt] [\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]) -# 488| [RegExpPlus] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]))+ +# 487| [RegExpPlus] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]))+ #-----| 0 -> [RegExpGroup] (?:[\s;,"'<>(){}|\[\]@=+*]|:(?![/\\])) -# 488| [RegExpCharacterClass] [\s;,"'<>(){}|\[\]@=+*] +# 487| [RegExpCharacterClass] [\s;,"'<>(){}|\[\]@=+*] #-----| 0 -> [RegExpCharacterClassEscape] \s #-----| 1 -> [RegExpConstant, RegExpNormalChar] ; #-----| 2 -> [RegExpConstant, RegExpNormalChar] , @@ -5171,183 +5279,231 @@ redos_variants.swift: #-----| 16 -> [RegExpConstant, RegExpNormalChar] + #-----| 17 -> [RegExpConstant, RegExpNormalChar] * -# 488| [RegExpAlt] [\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]) +# 487| [RegExpAlt] [\s;,"'<>(){}|\[\]@=+*]|:(?![/\\]) #-----| 0 -> [RegExpCharacterClass] [\s;,"'<>(){}|\[\]@=+*] #-----| 1 -> [RegExpSequence] :(?![/\\]) -# 488| [RegExpCharacterClassEscape] \s +# 487| [RegExpCharacterClassEscape] \s -# 488| [RegExpConstant, RegExpNormalChar] ; +# 487| [RegExpConstant, RegExpNormalChar] ; -# 488| [RegExpConstant, RegExpNormalChar] , +# 487| [RegExpConstant, RegExpNormalChar] , -# 488| [RegExpConstant, RegExpNormalChar] " +# 487| [RegExpConstant, RegExpNormalChar] " -# 488| [RegExpConstant, RegExpNormalChar] ' +# 487| [RegExpConstant, RegExpNormalChar] ' -# 488| [RegExpConstant, RegExpNormalChar] < +# 487| [RegExpConstant, RegExpNormalChar] < -# 488| [RegExpConstant, RegExpNormalChar] > +# 487| [RegExpConstant, RegExpNormalChar] > -# 488| [RegExpConstant, RegExpNormalChar] ( +# 487| [RegExpConstant, RegExpNormalChar] ( -# 488| [RegExpConstant, RegExpNormalChar] ) +# 487| [RegExpConstant, RegExpNormalChar] ) -# 488| [RegExpConstant, RegExpNormalChar] { +# 487| [RegExpConstant, RegExpNormalChar] { -# 488| [RegExpConstant, RegExpNormalChar] } +# 487| [RegExpConstant, RegExpNormalChar] } -# 488| [RegExpConstant, RegExpNormalChar] | +# 487| [RegExpConstant, RegExpNormalChar] | -# 488| [RegExpConstant, RegExpEscape] \[ +# 487| [RegExpConstant, RegExpEscape] \[ -# 488| [RegExpConstant, RegExpEscape] \] +# 487| [RegExpConstant, RegExpEscape] \] -# 488| [RegExpConstant, RegExpNormalChar] @ +# 487| [RegExpConstant, RegExpNormalChar] @ -# 488| [RegExpConstant, RegExpNormalChar] = +# 487| [RegExpConstant, RegExpNormalChar] = -# 488| [RegExpConstant, RegExpNormalChar] + +# 487| [RegExpConstant, RegExpNormalChar] + -# 488| [RegExpConstant, RegExpNormalChar] * +# 487| [RegExpConstant, RegExpNormalChar] * -# 488| [RegExpConstant, RegExpNormalChar] : +# 487| [RegExpConstant, RegExpNormalChar] : -# 488| [RegExpSequence] :(?![/\\]) +# 487| [RegExpSequence] :(?![/\\]) #-----| 0 -> [RegExpConstant, RegExpNormalChar] : #-----| 1 -> [RegExpNegativeLookahead] (?![/\\]) -# 488| [RegExpNegativeLookahead] (?![/\\]) +# 487| [RegExpNegativeLookahead] (?![/\\]) -# 488| [RegExpCharacterClass] [/\\] +# 487| [RegExpCharacterClass] [/\\] #-----| 0 -> [RegExpConstant, RegExpNormalChar] / #-----| 1 -> [RegExpConstant, RegExpEscape] \\ -# 488| [RegExpConstant, RegExpNormalChar] / +# 487| [RegExpConstant, RegExpNormalChar] / -# 488| [RegExpConstant, RegExpEscape] \\ +# 487| [RegExpConstant, RegExpEscape] \\ -# 492| [RegExpCaret] ^ +# 491| [RegExpCaret] ^ -# 492| [RegExpSequence] ^((?:a{|-)|\w\{)+X$ +# 491| [RegExpSequence] ^((?:a{|-)|\w\{)+X$ #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpPlus] ((?:a{|-)|\w\{)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] X #-----| 3 -> [RegExpDollar] $ -# 492| [RegExpGroup] ((?:a{|-)|\w\{) +# 491| [RegExpGroup] ((?:a{|-)|\w\{) #-----| 0 -> [RegExpAlt] (?:a{|-)|\w\{ -# 492| [RegExpPlus] ((?:a{|-)|\w\{)+ +# 491| [RegExpPlus] ((?:a{|-)|\w\{)+ #-----| 0 -> [RegExpGroup] ((?:a{|-)|\w\{) -# 492| [RegExpGroup] (?:a{|-) +# 491| [RegExpGroup] (?:a{|-) #-----| 0 -> [RegExpAlt] a{|- -# 492| [RegExpAlt] (?:a{|-)|\w\{ +# 491| [RegExpAlt] (?:a{|-)|\w\{ #-----| 0 -> [RegExpGroup] (?:a{|-) #-----| 1 -> [RegExpSequence] \w\{ -# 492| [RegExpConstant, RegExpNormalChar] a{ +# 491| [RegExpConstant, RegExpNormalChar] a{ -# 492| [RegExpAlt] a{|- +# 491| [RegExpAlt] a{|- #-----| 0 -> [RegExpConstant, RegExpNormalChar] a{ #-----| 1 -> [RegExpConstant, RegExpNormalChar] - +# 491| [RegExpConstant, RegExpNormalChar] - + +# 491| [RegExpCharacterClassEscape] \w + +# 491| [RegExpSequence] \w\{ +#-----| 0 -> [RegExpCharacterClassEscape] \w +#-----| 1 -> [RegExpConstant, RegExpEscape] \{ + +# 491| [RegExpConstant, RegExpEscape] \{ + +# 491| [RegExpConstant, RegExpNormalChar] X + +# 491| [RegExpDollar] $ + +# 492| [RegExpCaret] ^ + +# 492| [RegExpSequence] ^((?:a{0|-)|\w\{\d)+X$ +#-----| 0 -> [RegExpCaret] ^ +#-----| 1 -> [RegExpPlus] ((?:a{0|-)|\w\{\d)+ +#-----| 2 -> [RegExpConstant, RegExpNormalChar] X +#-----| 3 -> [RegExpDollar] $ + +# 492| [RegExpGroup] ((?:a{0|-)|\w\{\d) +#-----| 0 -> [RegExpAlt] (?:a{0|-)|\w\{\d + +# 492| [RegExpPlus] ((?:a{0|-)|\w\{\d)+ +#-----| 0 -> [RegExpGroup] ((?:a{0|-)|\w\{\d) + +# 492| [RegExpGroup] (?:a{0|-) +#-----| 0 -> [RegExpAlt] a{0|- + +# 492| [RegExpAlt] (?:a{0|-)|\w\{\d +#-----| 0 -> [RegExpGroup] (?:a{0|-) +#-----| 1 -> [RegExpSequence] \w\{\d + +# 492| [RegExpConstant, RegExpNormalChar] a{0 + +# 492| [RegExpAlt] a{0|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + # 492| [RegExpConstant, RegExpNormalChar] - # 492| [RegExpCharacterClassEscape] \w -# 492| [RegExpSequence] \w\{ +# 492| [RegExpSequence] \w\{\d #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpEscape] \{ +#-----| 2 -> [RegExpCharacterClassEscape] \d # 492| [RegExpConstant, RegExpEscape] \{ +# 492| [RegExpCharacterClassEscape] \d + # 492| [RegExpConstant, RegExpNormalChar] X # 492| [RegExpDollar] $ # 493| [RegExpCaret] ^ -# 493| [RegExpSequence] ^((?:a{0|-)|\w\{\d)+X$ +# 493| [RegExpSequence] ^((?:a{0,|-)|\w\{\d,)+X$ #-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpPlus] ((?:a{0|-)|\w\{\d)+ +#-----| 1 -> [RegExpPlus] ((?:a{0,|-)|\w\{\d,)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] X #-----| 3 -> [RegExpDollar] $ -# 493| [RegExpGroup] ((?:a{0|-)|\w\{\d) -#-----| 0 -> [RegExpAlt] (?:a{0|-)|\w\{\d +# 493| [RegExpGroup] ((?:a{0,|-)|\w\{\d,) +#-----| 0 -> [RegExpAlt] (?:a{0,|-)|\w\{\d, -# 493| [RegExpPlus] ((?:a{0|-)|\w\{\d)+ -#-----| 0 -> [RegExpGroup] ((?:a{0|-)|\w\{\d) +# 493| [RegExpPlus] ((?:a{0,|-)|\w\{\d,)+ +#-----| 0 -> [RegExpGroup] ((?:a{0,|-)|\w\{\d,) -# 493| [RegExpGroup] (?:a{0|-) -#-----| 0 -> [RegExpAlt] a{0|- +# 493| [RegExpGroup] (?:a{0,|-) +#-----| 0 -> [RegExpAlt] a{0,|- -# 493| [RegExpAlt] (?:a{0|-)|\w\{\d -#-----| 0 -> [RegExpGroup] (?:a{0|-) -#-----| 1 -> [RegExpSequence] \w\{\d +# 493| [RegExpAlt] (?:a{0,|-)|\w\{\d, +#-----| 0 -> [RegExpGroup] (?:a{0,|-) +#-----| 1 -> [RegExpSequence] \w\{\d, -# 493| [RegExpConstant, RegExpNormalChar] a{0 +# 493| [RegExpConstant, RegExpNormalChar] a{0, -# 493| [RegExpAlt] a{0|- -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0 +# 493| [RegExpAlt] a{0,|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0, #-----| 1 -> [RegExpConstant, RegExpNormalChar] - # 493| [RegExpConstant, RegExpNormalChar] - # 493| [RegExpCharacterClassEscape] \w -# 493| [RegExpSequence] \w\{\d +# 493| [RegExpSequence] \w\{\d, #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpEscape] \{ #-----| 2 -> [RegExpCharacterClassEscape] \d +#-----| 3 -> [RegExpConstant, RegExpNormalChar] , # 493| [RegExpConstant, RegExpEscape] \{ # 493| [RegExpCharacterClassEscape] \d +# 493| [RegExpConstant, RegExpNormalChar] , + # 493| [RegExpConstant, RegExpNormalChar] X # 493| [RegExpDollar] $ # 494| [RegExpCaret] ^ -# 494| [RegExpSequence] ^((?:a{0,|-)|\w\{\d,)+X$ +# 494| [RegExpSequence] ^((?:a{0,2|-)|\w\{\d,\d)+X$ #-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpPlus] ((?:a{0,|-)|\w\{\d,)+ +#-----| 1 -> [RegExpPlus] ((?:a{0,2|-)|\w\{\d,\d)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] X #-----| 3 -> [RegExpDollar] $ -# 494| [RegExpGroup] ((?:a{0,|-)|\w\{\d,) -#-----| 0 -> [RegExpAlt] (?:a{0,|-)|\w\{\d, +# 494| [RegExpGroup] ((?:a{0,2|-)|\w\{\d,\d) +#-----| 0 -> [RegExpAlt] (?:a{0,2|-)|\w\{\d,\d -# 494| [RegExpPlus] ((?:a{0,|-)|\w\{\d,)+ -#-----| 0 -> [RegExpGroup] ((?:a{0,|-)|\w\{\d,) +# 494| [RegExpPlus] ((?:a{0,2|-)|\w\{\d,\d)+ +#-----| 0 -> [RegExpGroup] ((?:a{0,2|-)|\w\{\d,\d) -# 494| [RegExpGroup] (?:a{0,|-) -#-----| 0 -> [RegExpAlt] a{0,|- +# 494| [RegExpGroup] (?:a{0,2|-) +#-----| 0 -> [RegExpAlt] a{0,2|- -# 494| [RegExpAlt] (?:a{0,|-)|\w\{\d, -#-----| 0 -> [RegExpGroup] (?:a{0,|-) -#-----| 1 -> [RegExpSequence] \w\{\d, +# 494| [RegExpAlt] (?:a{0,2|-)|\w\{\d,\d +#-----| 0 -> [RegExpGroup] (?:a{0,2|-) +#-----| 1 -> [RegExpSequence] \w\{\d,\d -# 494| [RegExpConstant, RegExpNormalChar] a{0, +# 494| [RegExpConstant, RegExpNormalChar] a{0,2 -# 494| [RegExpAlt] a{0,|- -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0, +# 494| [RegExpAlt] a{0,2|- +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0,2 #-----| 1 -> [RegExpConstant, RegExpNormalChar] - # 494| [RegExpConstant, RegExpNormalChar] - # 494| [RegExpCharacterClassEscape] \w -# 494| [RegExpSequence] \w\{\d, +# 494| [RegExpSequence] \w\{\d,\d #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpEscape] \{ #-----| 2 -> [RegExpCharacterClassEscape] \d #-----| 3 -> [RegExpConstant, RegExpNormalChar] , +#-----| 4 -> [RegExpCharacterClassEscape] \d # 494| [RegExpConstant, RegExpEscape] \{ @@ -5355,95 +5511,47 @@ redos_variants.swift: # 494| [RegExpConstant, RegExpNormalChar] , +# 494| [RegExpCharacterClassEscape] \d + # 494| [RegExpConstant, RegExpNormalChar] X # 494| [RegExpDollar] $ -# 495| [RegExpCaret] ^ +# 497| [RegExpCaret] ^ -# 495| [RegExpSequence] ^((?:a{0,2|-)|\w\{\d,\d)+X$ -#-----| 0 -> [RegExpCaret] ^ -#-----| 1 -> [RegExpPlus] ((?:a{0,2|-)|\w\{\d,\d)+ -#-----| 2 -> [RegExpConstant, RegExpNormalChar] X -#-----| 3 -> [RegExpDollar] $ - -# 495| [RegExpGroup] ((?:a{0,2|-)|\w\{\d,\d) -#-----| 0 -> [RegExpAlt] (?:a{0,2|-)|\w\{\d,\d - -# 495| [RegExpPlus] ((?:a{0,2|-)|\w\{\d,\d)+ -#-----| 0 -> [RegExpGroup] ((?:a{0,2|-)|\w\{\d,\d) - -# 495| [RegExpGroup] (?:a{0,2|-) -#-----| 0 -> [RegExpAlt] a{0,2|- - -# 495| [RegExpAlt] (?:a{0,2|-)|\w\{\d,\d -#-----| 0 -> [RegExpGroup] (?:a{0,2|-) -#-----| 1 -> [RegExpSequence] \w\{\d,\d - -# 495| [RegExpConstant, RegExpNormalChar] a{0,2 - -# 495| [RegExpAlt] a{0,2|- -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a{0,2 -#-----| 1 -> [RegExpConstant, RegExpNormalChar] - - -# 495| [RegExpConstant, RegExpNormalChar] - - -# 495| [RegExpCharacterClassEscape] \w - -# 495| [RegExpSequence] \w\{\d,\d -#-----| 0 -> [RegExpCharacterClassEscape] \w -#-----| 1 -> [RegExpConstant, RegExpEscape] \{ -#-----| 2 -> [RegExpCharacterClassEscape] \d -#-----| 3 -> [RegExpConstant, RegExpNormalChar] , -#-----| 4 -> [RegExpCharacterClassEscape] \d - -# 495| [RegExpConstant, RegExpEscape] \{ - -# 495| [RegExpCharacterClassEscape] \d - -# 495| [RegExpConstant, RegExpNormalChar] , - -# 495| [RegExpCharacterClassEscape] \d - -# 495| [RegExpConstant, RegExpNormalChar] X - -# 495| [RegExpDollar] $ - -# 498| [RegExpCaret] ^ - -# 498| [RegExpSequence] ^((?:a{0,2}|-)|\w\{\d,\d\})+X$ +# 497| [RegExpSequence] ^((?:a{0,2}|-)|\w\{\d,\d\})+X$ #-----| 0 -> [RegExpCaret] ^ #-----| 1 -> [RegExpPlus] ((?:a{0,2}|-)|\w\{\d,\d\})+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] X #-----| 3 -> [RegExpDollar] $ -# 498| [RegExpGroup] ((?:a{0,2}|-)|\w\{\d,\d\}) +# 497| [RegExpGroup] ((?:a{0,2}|-)|\w\{\d,\d\}) #-----| 0 -> [RegExpAlt] (?:a{0,2}|-)|\w\{\d,\d\} -# 498| [RegExpPlus] ((?:a{0,2}|-)|\w\{\d,\d\})+ +# 497| [RegExpPlus] ((?:a{0,2}|-)|\w\{\d,\d\})+ #-----| 0 -> [RegExpGroup] ((?:a{0,2}|-)|\w\{\d,\d\}) -# 498| [RegExpGroup] (?:a{0,2}|-) +# 497| [RegExpGroup] (?:a{0,2}|-) #-----| 0 -> [RegExpAlt] a{0,2}|- -# 498| [RegExpAlt] (?:a{0,2}|-)|\w\{\d,\d\} +# 497| [RegExpAlt] (?:a{0,2}|-)|\w\{\d,\d\} #-----| 0 -> [RegExpGroup] (?:a{0,2}|-) #-----| 1 -> [RegExpSequence] \w\{\d,\d\} -# 498| [RegExpConstant, RegExpNormalChar] a +# 497| [RegExpConstant, RegExpNormalChar] a -# 498| [RegExpRange] a{0,2} +# 497| [RegExpRange] a{0,2} #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 498| [RegExpAlt] a{0,2}|- +# 497| [RegExpAlt] a{0,2}|- #-----| 0 -> [RegExpRange] a{0,2} #-----| 1 -> [RegExpConstant, RegExpNormalChar] - -# 498| [RegExpConstant, RegExpNormalChar] - +# 497| [RegExpConstant, RegExpNormalChar] - -# 498| [RegExpCharacterClassEscape] \w +# 497| [RegExpCharacterClassEscape] \w -# 498| [RegExpSequence] \w\{\d,\d\} +# 497| [RegExpSequence] \w\{\d,\d\} #-----| 0 -> [RegExpCharacterClassEscape] \w #-----| 1 -> [RegExpConstant, RegExpEscape] \{ #-----| 2 -> [RegExpCharacterClassEscape] \d @@ -5451,546 +5559,615 @@ redos_variants.swift: #-----| 4 -> [RegExpCharacterClassEscape] \d #-----| 5 -> [RegExpConstant, RegExpEscape] \} -# 498| [RegExpConstant, RegExpEscape] \{ +# 497| [RegExpConstant, RegExpEscape] \{ -# 498| [RegExpCharacterClassEscape] \d +# 497| [RegExpCharacterClassEscape] \d -# 498| [RegExpConstant, RegExpNormalChar] , +# 497| [RegExpConstant, RegExpNormalChar] , -# 498| [RegExpCharacterClassEscape] \d +# 497| [RegExpCharacterClassEscape] \d -# 498| [RegExpConstant, RegExpEscape] \} +# 497| [RegExpConstant, RegExpEscape] \} -# 498| [RegExpConstant, RegExpNormalChar] X +# 497| [RegExpConstant, RegExpNormalChar] X -# 498| [RegExpDollar] $ +# 497| [RegExpDollar] $ -# 502| [RegExpConstant, RegExpNormalChar] X +# 501| [RegExpConstant, RegExpNormalChar] X -# 502| [RegExpSequence] X(\u0061|a)*Y +# 501| [RegExpSequence] X(\u0061|a)*Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpStar] (\u0061|a)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 502| [RegExpGroup] (\u0061|a) +# 501| [RegExpGroup] (\u0061|a) #-----| 0 -> [RegExpAlt] \u0061|a -# 502| [RegExpStar] (\u0061|a)* +# 501| [RegExpStar] (\u0061|a)* #-----| 0 -> [RegExpGroup] (\u0061|a) -# 502| [RegExpConstant, RegExpEscape] \u0061 +# 501| [RegExpConstant, RegExpEscape] \u0061 -# 502| [RegExpAlt] \u0061|a +# 501| [RegExpAlt] \u0061|a #-----| 0 -> [RegExpConstant, RegExpEscape] \u0061 #-----| 1 -> [RegExpConstant, RegExpNormalChar] a -# 502| [RegExpConstant, RegExpNormalChar] a +# 501| [RegExpConstant, RegExpNormalChar] a -# 502| [RegExpConstant, RegExpNormalChar] Y +# 501| [RegExpConstant, RegExpNormalChar] Y -# 505| [RegExpConstant, RegExpNormalChar] X +# 504| [RegExpConstant, RegExpNormalChar] X -# 505| [RegExpSequence] X(\u0061|b)+Y +# 504| [RegExpSequence] X(\u0061|b)+Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpPlus] (\u0061|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 505| [RegExpGroup] (\u0061|b) +# 504| [RegExpGroup] (\u0061|b) #-----| 0 -> [RegExpAlt] \u0061|b -# 505| [RegExpPlus] (\u0061|b)+ +# 504| [RegExpPlus] (\u0061|b)+ #-----| 0 -> [RegExpGroup] (\u0061|b) -# 505| [RegExpConstant, RegExpEscape] \u0061 +# 504| [RegExpConstant, RegExpEscape] \u0061 -# 505| [RegExpAlt] \u0061|b +# 504| [RegExpAlt] \u0061|b #-----| 0 -> [RegExpConstant, RegExpEscape] \u0061 #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 505| [RegExpConstant, RegExpNormalChar] b +# 504| [RegExpConstant, RegExpNormalChar] b -# 505| [RegExpConstant, RegExpNormalChar] Y +# 504| [RegExpConstant, RegExpNormalChar] Y -# 509| [RegExpConstant, RegExpNormalChar] X +# 508| [RegExpConstant, RegExpNormalChar] X -# 509| [RegExpSequence] X(\U00000061|a)*Y +# 508| [RegExpSequence] X(\U00000061|a)*Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpStar] (\U00000061|a)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 509| [RegExpGroup] (\U00000061|a) +# 508| [RegExpGroup] (\U00000061|a) #-----| 0 -> [RegExpAlt] \U00000061|a -# 509| [RegExpStar] (\U00000061|a)* +# 508| [RegExpStar] (\U00000061|a)* #-----| 0 -> [RegExpGroup] (\U00000061|a) -# 509| [RegExpConstant, RegExpEscape] \U00000061 +# 508| [RegExpConstant, RegExpEscape] \U00000061 -# 509| [RegExpAlt] \U00000061|a +# 508| [RegExpAlt] \U00000061|a #-----| 0 -> [RegExpConstant, RegExpEscape] \U00000061 #-----| 1 -> [RegExpConstant, RegExpNormalChar] a -# 509| [RegExpConstant, RegExpNormalChar] a +# 508| [RegExpConstant, RegExpNormalChar] a -# 509| [RegExpConstant, RegExpNormalChar] Y +# 508| [RegExpConstant, RegExpNormalChar] Y -# 512| [RegExpConstant, RegExpNormalChar] X +# 511| [RegExpConstant, RegExpNormalChar] X -# 512| [RegExpSequence] X(\U00000061|b)+Y +# 511| [RegExpSequence] X(\U00000061|b)+Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpPlus] (\U00000061|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 512| [RegExpGroup] (\U00000061|b) +# 511| [RegExpGroup] (\U00000061|b) #-----| 0 -> [RegExpAlt] \U00000061|b -# 512| [RegExpPlus] (\U00000061|b)+ +# 511| [RegExpPlus] (\U00000061|b)+ #-----| 0 -> [RegExpGroup] (\U00000061|b) -# 512| [RegExpConstant, RegExpEscape] \U00000061 +# 511| [RegExpConstant, RegExpEscape] \U00000061 -# 512| [RegExpAlt] \U00000061|b +# 511| [RegExpAlt] \U00000061|b #-----| 0 -> [RegExpConstant, RegExpEscape] \U00000061 #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 512| [RegExpConstant, RegExpNormalChar] b +# 511| [RegExpConstant, RegExpNormalChar] b -# 512| [RegExpConstant, RegExpNormalChar] Y +# 511| [RegExpConstant, RegExpNormalChar] Y -# 516| [RegExpConstant, RegExpNormalChar] X +# 515| [RegExpConstant, RegExpNormalChar] X -# 516| [RegExpSequence] X(\x61|a)*Y +# 515| [RegExpSequence] X(\x61|a)*Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpStar] (\x61|a)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 516| [RegExpGroup] (\x61|a) +# 515| [RegExpGroup] (\x61|a) #-----| 0 -> [RegExpAlt] \x61|a -# 516| [RegExpStar] (\x61|a)* +# 515| [RegExpStar] (\x61|a)* #-----| 0 -> [RegExpGroup] (\x61|a) -# 516| [RegExpConstant, RegExpEscape] \x61 +# 515| [RegExpConstant, RegExpEscape] \x61 -# 516| [RegExpAlt] \x61|a +# 515| [RegExpAlt] \x61|a #-----| 0 -> [RegExpConstant, RegExpEscape] \x61 #-----| 1 -> [RegExpConstant, RegExpNormalChar] a -# 516| [RegExpConstant, RegExpNormalChar] a +# 515| [RegExpConstant, RegExpNormalChar] a -# 516| [RegExpConstant, RegExpNormalChar] Y +# 515| [RegExpConstant, RegExpNormalChar] Y -# 519| [RegExpConstant, RegExpNormalChar] X +# 518| [RegExpConstant, RegExpNormalChar] X -# 519| [RegExpSequence] X(\x61|b)+Y +# 518| [RegExpSequence] X(\x61|b)+Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpPlus] (\x61|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 519| [RegExpGroup] (\x61|b) +# 518| [RegExpGroup] (\x61|b) #-----| 0 -> [RegExpAlt] \x61|b -# 519| [RegExpPlus] (\x61|b)+ +# 518| [RegExpPlus] (\x61|b)+ #-----| 0 -> [RegExpGroup] (\x61|b) -# 519| [RegExpConstant, RegExpEscape] \x61 +# 518| [RegExpConstant, RegExpEscape] \x61 -# 519| [RegExpAlt] \x61|b +# 518| [RegExpAlt] \x61|b #-----| 0 -> [RegExpConstant, RegExpEscape] \x61 #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 519| [RegExpConstant, RegExpNormalChar] b +# 518| [RegExpConstant, RegExpNormalChar] b -# 519| [RegExpConstant, RegExpNormalChar] Y +# 518| [RegExpConstant, RegExpNormalChar] Y -# 523| [RegExpConstant, RegExpNormalChar] X +# 522| [RegExpConstant, RegExpNormalChar] X -# 523| [RegExpSequence] X(\x{061}|a)*Y +# 522| [RegExpSequence] X(\x{061}|a)*Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpStar] (\x{061}|a)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 523| [RegExpGroup] (\x{061}|a) +# 522| [RegExpGroup] (\x{061}|a) #-----| 0 -> [RegExpAlt] \x{061}|a -# 523| [RegExpStar] (\x{061}|a)* +# 522| [RegExpStar] (\x{061}|a)* #-----| 0 -> [RegExpGroup] (\x{061}|a) -# 523| [RegExpConstant, RegExpEscape] \x{0 +# 522| [RegExpConstant, RegExpEscape] \x{0 -# 523| [RegExpConstant, RegExpEscape] \x{061} +# 522| [RegExpConstant, RegExpEscape] \x{061} -# 523| [RegExpAlt] \x{061}|a +# 522| [RegExpAlt] \x{061}|a #-----| 0 -> [RegExpConstant, RegExpEscape] \x{0 #-----| 0 -> [RegExpConstant, RegExpEscape] \x{061} #-----| 1 -> [RegExpConstant, RegExpNormalChar] a -# 523| [RegExpConstant, RegExpNormalChar] a +# 522| [RegExpConstant, RegExpNormalChar] a -# 523| [RegExpConstant, RegExpNormalChar] Y +# 522| [RegExpConstant, RegExpNormalChar] Y -# 526| [RegExpConstant, RegExpNormalChar] X +# 525| [RegExpConstant, RegExpNormalChar] X -# 526| [RegExpSequence] X(\x{061}|b)+Y +# 525| [RegExpSequence] X(\x{061}|b)+Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpPlus] (\x{061}|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 526| [RegExpGroup] (\x{061}|b) +# 525| [RegExpGroup] (\x{061}|b) #-----| 0 -> [RegExpAlt] \x{061}|b -# 526| [RegExpPlus] (\x{061}|b)+ +# 525| [RegExpPlus] (\x{061}|b)+ #-----| 0 -> [RegExpGroup] (\x{061}|b) -# 526| [RegExpConstant, RegExpEscape] \x{0 +# 525| [RegExpConstant, RegExpEscape] \x{0 -# 526| [RegExpConstant, RegExpEscape] \x{061} +# 525| [RegExpConstant, RegExpEscape] \x{061} -# 526| [RegExpAlt] \x{061}|b +# 525| [RegExpAlt] \x{061}|b #-----| 0 -> [RegExpConstant, RegExpEscape] \x{0 #-----| 0 -> [RegExpConstant, RegExpEscape] \x{061} #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 526| [RegExpConstant, RegExpNormalChar] b +# 525| [RegExpConstant, RegExpNormalChar] b -# 526| [RegExpConstant, RegExpNormalChar] Y +# 525| [RegExpConstant, RegExpNormalChar] Y -# 530| [RegExpConstant, RegExpNormalChar] X +# 529| [RegExpConstant, RegExpNormalChar] X -# 530| [RegExpSequence] X(\p{Digit}|7)*Y +# 529| [RegExpSequence] X(\p{Digit}|7)*Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpStar] (\p{Digit}|7)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 530| [RegExpGroup] (\p{Digit}|7) +# 529| [RegExpGroup] (\p{Digit}|7) #-----| 0 -> [RegExpAlt] \p{Digit}|7 -# 530| [RegExpStar] (\p{Digit}|7)* +# 529| [RegExpStar] (\p{Digit}|7)* #-----| 0 -> [RegExpGroup] (\p{Digit}|7) -# 530| [RegExpNamedCharacterProperty] \p{Digit} +# 529| [RegExpNamedCharacterProperty] \p{Digit} -# 530| [RegExpAlt] \p{Digit}|7 +# 529| [RegExpAlt] \p{Digit}|7 #-----| 0 -> [RegExpNamedCharacterProperty] \p{Digit} #-----| 1 -> [RegExpConstant, RegExpNormalChar] 7 -# 530| [RegExpAlt] |7 +# 529| [RegExpAlt] |7 -# 530| [RegExpConstant, RegExpNormalChar] 7 +# 529| [RegExpConstant, RegExpNormalChar] 7 -# 530| [RegExpConstant, RegExpNormalChar] Y +# 529| [RegExpConstant, RegExpNormalChar] Y -# 533| [RegExpConstant, RegExpNormalChar] X +# 532| [RegExpConstant, RegExpNormalChar] X -# 533| [RegExpSequence] X(\p{Digit}|b)+Y +# 532| [RegExpSequence] X(\p{Digit}|b)+Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpPlus] (\p{Digit}|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 533| [RegExpGroup] (\p{Digit}|b) +# 532| [RegExpGroup] (\p{Digit}|b) #-----| 0 -> [RegExpAlt] \p{Digit}|b -# 533| [RegExpPlus] (\p{Digit}|b)+ +# 532| [RegExpPlus] (\p{Digit}|b)+ #-----| 0 -> [RegExpGroup] (\p{Digit}|b) -# 533| [RegExpNamedCharacterProperty] \p{Digit} +# 532| [RegExpNamedCharacterProperty] \p{Digit} -# 533| [RegExpAlt] \p{Digit}|b +# 532| [RegExpAlt] \p{Digit}|b #-----| 0 -> [RegExpNamedCharacterProperty] \p{Digit} #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 533| [RegExpAlt] |b +# 532| [RegExpAlt] |b -# 533| [RegExpConstant, RegExpNormalChar] b +# 532| [RegExpConstant, RegExpNormalChar] b -# 533| [RegExpConstant, RegExpNormalChar] Y +# 532| [RegExpConstant, RegExpNormalChar] Y -# 537| [RegExpConstant, RegExpNormalChar] X +# 536| [RegExpConstant, RegExpNormalChar] X -# 537| [RegExpSequence] X(\P{Digit}|b)*Y +# 536| [RegExpSequence] X(\P{Digit}|b)*Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpStar] (\P{Digit}|b)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 537| [RegExpGroup] (\P{Digit}|b) +# 536| [RegExpGroup] (\P{Digit}|b) #-----| 0 -> [RegExpAlt] \P{Digit}|b -# 537| [RegExpStar] (\P{Digit}|b)* +# 536| [RegExpStar] (\P{Digit}|b)* #-----| 0 -> [RegExpGroup] (\P{Digit}|b) -# 537| [RegExpNamedCharacterProperty] \P{Digit} +# 536| [RegExpNamedCharacterProperty] \P{Digit} -# 537| [RegExpAlt] \P{Digit}|b +# 536| [RegExpAlt] \P{Digit}|b #-----| 0 -> [RegExpNamedCharacterProperty] \P{Digit} #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 537| [RegExpAlt] |b +# 536| [RegExpAlt] |b -# 537| [RegExpConstant, RegExpNormalChar] b +# 536| [RegExpConstant, RegExpNormalChar] b -# 537| [RegExpConstant, RegExpNormalChar] Y +# 536| [RegExpConstant, RegExpNormalChar] Y -# 540| [RegExpConstant, RegExpNormalChar] X +# 539| [RegExpConstant, RegExpNormalChar] X -# 540| [RegExpSequence] X(\P{Digit}|7)+Y +# 539| [RegExpSequence] X(\P{Digit}|7)+Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpPlus] (\P{Digit}|7)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 540| [RegExpGroup] (\P{Digit}|7) +# 539| [RegExpGroup] (\P{Digit}|7) #-----| 0 -> [RegExpAlt] \P{Digit}|7 -# 540| [RegExpPlus] (\P{Digit}|7)+ +# 539| [RegExpPlus] (\P{Digit}|7)+ #-----| 0 -> [RegExpGroup] (\P{Digit}|7) -# 540| [RegExpNamedCharacterProperty] \P{Digit} +# 539| [RegExpNamedCharacterProperty] \P{Digit} -# 540| [RegExpAlt] \P{Digit}|7 +# 539| [RegExpAlt] \P{Digit}|7 #-----| 0 -> [RegExpNamedCharacterProperty] \P{Digit} #-----| 1 -> [RegExpConstant, RegExpNormalChar] 7 -# 540| [RegExpAlt] |7 +# 539| [RegExpAlt] |7 -# 540| [RegExpConstant, RegExpNormalChar] 7 +# 539| [RegExpConstant, RegExpNormalChar] 7 -# 540| [RegExpConstant, RegExpNormalChar] Y +# 539| [RegExpConstant, RegExpNormalChar] Y -# 544| [RegExpConstant, RegExpNormalChar] X +# 543| [RegExpConstant, RegExpNormalChar] X -# 544| [RegExpSequence] X(\p{IsDigit}|7)*Y +# 543| [RegExpSequence] X(\p{IsDigit}|7)*Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpStar] (\p{IsDigit}|7)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 544| [RegExpGroup] (\p{IsDigit}|7) +# 543| [RegExpGroup] (\p{IsDigit}|7) #-----| 0 -> [RegExpAlt] \p{IsDigit}|7 -# 544| [RegExpStar] (\p{IsDigit}|7)* +# 543| [RegExpStar] (\p{IsDigit}|7)* #-----| 0 -> [RegExpGroup] (\p{IsDigit}|7) -# 544| [RegExpNamedCharacterProperty] \p{IsDigit} +# 543| [RegExpNamedCharacterProperty] \p{IsDigit} -# 544| [RegExpAlt] \p{IsDigit}|7 +# 543| [RegExpAlt] \p{IsDigit}|7 #-----| 0 -> [RegExpNamedCharacterProperty] \p{IsDigit} #-----| 1 -> [RegExpConstant, RegExpNormalChar] 7 -# 544| [RegExpAlt] |7 +# 543| [RegExpAlt] |7 -# 544| [RegExpConstant, RegExpNormalChar] 7 +# 543| [RegExpConstant, RegExpNormalChar] 7 -# 544| [RegExpConstant, RegExpNormalChar] Y +# 543| [RegExpConstant, RegExpNormalChar] Y -# 547| [RegExpConstant, RegExpNormalChar] X +# 546| [RegExpConstant, RegExpNormalChar] X -# 547| [RegExpSequence] X(\p{IsDigit}|b)+Y +# 546| [RegExpSequence] X(\p{IsDigit}|b)+Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpPlus] (\p{IsDigit}|b)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 547| [RegExpGroup] (\p{IsDigit}|b) +# 546| [RegExpGroup] (\p{IsDigit}|b) #-----| 0 -> [RegExpAlt] \p{IsDigit}|b -# 547| [RegExpPlus] (\p{IsDigit}|b)+ +# 546| [RegExpPlus] (\p{IsDigit}|b)+ #-----| 0 -> [RegExpGroup] (\p{IsDigit}|b) -# 547| [RegExpNamedCharacterProperty] \p{IsDigit} +# 546| [RegExpNamedCharacterProperty] \p{IsDigit} -# 547| [RegExpAlt] \p{IsDigit}|b +# 546| [RegExpAlt] \p{IsDigit}|b #-----| 0 -> [RegExpNamedCharacterProperty] \p{IsDigit} #-----| 1 -> [RegExpConstant, RegExpNormalChar] b -# 547| [RegExpAlt] |b +# 546| [RegExpAlt] |b -# 547| [RegExpConstant, RegExpNormalChar] b +# 546| [RegExpConstant, RegExpNormalChar] b -# 547| [RegExpConstant, RegExpNormalChar] Y +# 546| [RegExpConstant, RegExpNormalChar] Y -# 551| [RegExpConstant, RegExpNormalChar] X +# 550| [RegExpConstant, RegExpNormalChar] X -# 551| [RegExpSequence] X(\p{Alpha}|a)*Y +# 550| [RegExpSequence] X(\p{Alpha}|a)*Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpStar] (\p{Alpha}|a)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 551| [RegExpGroup] (\p{Alpha}|a) +# 550| [RegExpGroup] (\p{Alpha}|a) #-----| 0 -> [RegExpAlt] \p{Alpha}|a -# 551| [RegExpStar] (\p{Alpha}|a)* +# 550| [RegExpStar] (\p{Alpha}|a)* #-----| 0 -> [RegExpGroup] (\p{Alpha}|a) -# 551| [RegExpNamedCharacterProperty] \p{Alpha} +# 550| [RegExpNamedCharacterProperty] \p{Alpha} -# 551| [RegExpAlt] \p{Alpha}|a +# 550| [RegExpAlt] \p{Alpha}|a #-----| 0 -> [RegExpNamedCharacterProperty] \p{Alpha} #-----| 1 -> [RegExpConstant, RegExpNormalChar] a -# 551| [RegExpAlt] |a +# 550| [RegExpAlt] |a -# 551| [RegExpConstant, RegExpNormalChar] a +# 550| [RegExpConstant, RegExpNormalChar] a -# 551| [RegExpConstant, RegExpNormalChar] Y +# 550| [RegExpConstant, RegExpNormalChar] Y -# 554| [RegExpConstant, RegExpNormalChar] X +# 553| [RegExpConstant, RegExpNormalChar] X -# 554| [RegExpSequence] X(\p{Alpha}|7)+Y +# 553| [RegExpSequence] X(\p{Alpha}|7)+Y #-----| 0 -> [RegExpConstant, RegExpNormalChar] X #-----| 1 -> [RegExpPlus] (\p{Alpha}|7)+ #-----| 2 -> [RegExpConstant, RegExpNormalChar] Y -# 554| [RegExpGroup] (\p{Alpha}|7) +# 553| [RegExpGroup] (\p{Alpha}|7) #-----| 0 -> [RegExpAlt] \p{Alpha}|7 -# 554| [RegExpPlus] (\p{Alpha}|7)+ +# 553| [RegExpPlus] (\p{Alpha}|7)+ #-----| 0 -> [RegExpGroup] (\p{Alpha}|7) -# 554| [RegExpNamedCharacterProperty] \p{Alpha} +# 553| [RegExpNamedCharacterProperty] \p{Alpha} -# 554| [RegExpAlt] \p{Alpha}|7 +# 553| [RegExpAlt] \p{Alpha}|7 #-----| 0 -> [RegExpNamedCharacterProperty] \p{Alpha} #-----| 1 -> [RegExpConstant, RegExpNormalChar] 7 -# 554| [RegExpAlt] |7 +# 553| [RegExpAlt] |7 -# 554| [RegExpConstant, RegExpNormalChar] 7 +# 553| [RegExpConstant, RegExpNormalChar] 7 -# 554| [RegExpConstant, RegExpNormalChar] Y +# 553| [RegExpConstant, RegExpNormalChar] Y -# 557| [RegExpGroup] ("[^"]*?"|[^"\s]+) +# 556| [RegExpGroup] ("[^"]*?"|[^"\s]+) #-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ -# 557| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +# 556| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ #-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) -# 557| [RegExpSequence] ("[^"]*?"|[^"\s]+)+(?=\s*|\s*$) +# 556| [RegExpSequence] ("[^"]*?"|[^"\s]+)+(?=\s*|\s*$) #-----| 0 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ #-----| 1 -> [RegExpPositiveLookahead] (?=\s*|\s*$) -# 557| [RegExpConstant, RegExpNormalChar] " +# 556| [RegExpConstant, RegExpNormalChar] " -# 557| [RegExpSequence] "[^"]*?" +# 556| [RegExpSequence] "[^"]*?" #-----| 0 -> [RegExpConstant, RegExpNormalChar] " #-----| 1 -> [RegExpStar] [^"]*? #-----| 2 -> [RegExpConstant, RegExpNormalChar] " -# 557| [RegExpAlt] "[^"]*?"|[^"\s]+ +# 556| [RegExpAlt] "[^"]*?"|[^"\s]+ #-----| 0 -> [RegExpSequence] "[^"]*?" #-----| 1 -> [RegExpPlus] [^"\s]+ -# 557| [RegExpCharacterClass] [^"] +# 556| [RegExpCharacterClass] [^"] #-----| 0 -> [RegExpConstant, RegExpNormalChar] " -# 557| [RegExpStar] [^"]*? +# 556| [RegExpStar] [^"]*? #-----| 0 -> [RegExpCharacterClass] [^"] -# 557| [RegExpConstant, RegExpNormalChar] " +# 556| [RegExpConstant, RegExpNormalChar] " -# 557| [RegExpConstant, RegExpNormalChar] " +# 556| [RegExpConstant, RegExpNormalChar] " -# 557| [RegExpCharacterClass] [^"\s] +# 556| [RegExpCharacterClass] [^"\s] #-----| 0 -> [RegExpConstant, RegExpNormalChar] " #-----| 1 -> [RegExpCharacterClassEscape] \s -# 557| [RegExpPlus] [^"\s]+ +# 556| [RegExpPlus] [^"\s]+ #-----| 0 -> [RegExpCharacterClass] [^"\s] -# 557| [RegExpConstant, RegExpNormalChar] " +# 556| [RegExpConstant, RegExpNormalChar] " -# 557| [RegExpCharacterClassEscape] \s +# 556| [RegExpCharacterClassEscape] \s -# 557| [RegExpPositiveLookahead] (?=\s*|\s*$) +# 556| [RegExpPositiveLookahead] (?=\s*|\s*$) -# 557| [RegExpCharacterClassEscape] \s +# 556| [RegExpCharacterClassEscape] \s -# 557| [RegExpStar] \s* +# 556| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s -# 557| [RegExpAlt] \s*|\s*$ +# 556| [RegExpAlt] \s*|\s*$ #-----| 0 -> [RegExpStar] \s* #-----| 1 -> [RegExpSequence] \s*$ -# 557| [RegExpCharacterClassEscape] \s +# 556| [RegExpCharacterClassEscape] \s -# 557| [RegExpStar] \s* +# 556| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s -# 557| [RegExpSequence] \s*$ +# 556| [RegExpSequence] \s*$ #-----| 0 -> [RegExpStar] \s* #-----| 1 -> [RegExpDollar] $ -# 557| [RegExpDollar] $ +# 556| [RegExpDollar] $ -# 560| [RegExpGroup] ("[^"]*?"|[^"\s]+) +# 559| [RegExpGroup] ("[^"]*?"|[^"\s]+) #-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ -# 560| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +# 559| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ #-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) -# 560| [RegExpSequence] ("[^"]*?"|[^"\s]+)+(?=\s*|\s*$) +# 559| [RegExpSequence] ("[^"]*?"|[^"\s]+)+(?=\s*|\s*$) #-----| 0 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ #-----| 1 -> [RegExpPositiveLookahead] (?=\s*|\s*$) -# 560| [RegExpConstant, RegExpNormalChar] " +# 559| [RegExpConstant, RegExpNormalChar] " -# 560| [RegExpSequence] "[^"]*?" +# 559| [RegExpSequence] "[^"]*?" #-----| 0 -> [RegExpConstant, RegExpNormalChar] " #-----| 1 -> [RegExpStar] [^"]*? #-----| 2 -> [RegExpConstant, RegExpNormalChar] " -# 560| [RegExpAlt] "[^"]*?"|[^"\s]+ +# 559| [RegExpAlt] "[^"]*?"|[^"\s]+ #-----| 0 -> [RegExpSequence] "[^"]*?" #-----| 1 -> [RegExpPlus] [^"\s]+ -# 560| [RegExpCharacterClass] [^"] +# 559| [RegExpCharacterClass] [^"] #-----| 0 -> [RegExpConstant, RegExpNormalChar] " -# 560| [RegExpStar] [^"]*? +# 559| [RegExpStar] [^"]*? #-----| 0 -> [RegExpCharacterClass] [^"] -# 560| [RegExpConstant, RegExpNormalChar] " +# 559| [RegExpConstant, RegExpNormalChar] " -# 560| [RegExpConstant, RegExpNormalChar] " +# 559| [RegExpConstant, RegExpNormalChar] " -# 560| [RegExpCharacterClass] [^"\s] +# 559| [RegExpCharacterClass] [^"\s] #-----| 0 -> [RegExpConstant, RegExpNormalChar] " #-----| 1 -> [RegExpCharacterClassEscape] \s -# 560| [RegExpPlus] [^"\s]+ +# 559| [RegExpPlus] [^"\s]+ #-----| 0 -> [RegExpCharacterClass] [^"\s] -# 560| [RegExpConstant, RegExpNormalChar] " +# 559| [RegExpConstant, RegExpNormalChar] " -# 560| [RegExpCharacterClassEscape] \s +# 559| [RegExpCharacterClassEscape] \s -# 560| [RegExpPositiveLookahead] (?=\s*|\s*$) +# 559| [RegExpPositiveLookahead] (?=\s*|\s*$) -# 560| [RegExpCharacterClassEscape] \s +# 559| [RegExpCharacterClassEscape] \s -# 560| [RegExpStar] \s* +# 559| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s -# 560| [RegExpAlt] \s*|\s*$ +# 559| [RegExpAlt] \s*|\s*$ #-----| 0 -> [RegExpStar] \s* #-----| 1 -> [RegExpSequence] \s*$ -# 560| [RegExpCharacterClassEscape] \s +# 559| [RegExpCharacterClassEscape] \s -# 560| [RegExpStar] \s* +# 559| [RegExpStar] \s* #-----| 0 -> [RegExpCharacterClassEscape] \s -# 560| [RegExpSequence] \s*$ +# 559| [RegExpSequence] \s*$ #-----| 0 -> [RegExpStar] \s* #-----| 1 -> [RegExpDollar] $ -# 560| [RegExpDollar] $ +# 559| [RegExpDollar] $ -# 564| [RegExpConstant, RegExpNormalChar] / +# 563| [RegExpConstant, RegExpNormalChar] / -# 564| [RegExpSequence] /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X +# 563| [RegExpSequence] /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X #-----| 0 -> [RegExpConstant, RegExpNormalChar] / #-----| 1 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ #-----| 2 -> [RegExpPositiveLookahead] (?=\s*|\s*$) #-----| 3 -> [RegExpConstant, RegExpNormalChar] X +# 563| [RegExpGroup] ("[^"]*?"|[^"\s]+) +#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ + +# 563| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) + +# 563| [RegExpConstant, RegExpNormalChar] " + +# 563| [RegExpSequence] "[^"]*?" +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpStar] [^"]*? +#-----| 2 -> [RegExpConstant, RegExpNormalChar] " + +# 563| [RegExpAlt] "[^"]*?"|[^"\s]+ +#-----| 0 -> [RegExpSequence] "[^"]*?" +#-----| 1 -> [RegExpPlus] [^"\s]+ + +# 563| [RegExpCharacterClass] [^"] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " + +# 563| [RegExpStar] [^"]*? +#-----| 0 -> [RegExpCharacterClass] [^"] + +# 563| [RegExpConstant, RegExpNormalChar] " + +# 563| [RegExpConstant, RegExpNormalChar] " + +# 563| [RegExpCharacterClass] [^"\s] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] " +#-----| 1 -> [RegExpCharacterClassEscape] \s + +# 563| [RegExpPlus] [^"\s]+ +#-----| 0 -> [RegExpCharacterClass] [^"\s] + +# 563| [RegExpConstant, RegExpNormalChar] " + +# 563| [RegExpCharacterClassEscape] \s + +# 563| [RegExpPositiveLookahead] (?=\s*|\s*$) + +# 563| [RegExpCharacterClassEscape] \s + +# 563| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 563| [RegExpAlt] \s*|\s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpSequence] \s*$ + +# 563| [RegExpCharacterClassEscape] \s + +# 563| [RegExpStar] \s* +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 563| [RegExpSequence] \s*$ +#-----| 0 -> [RegExpStar] \s* +#-----| 1 -> [RegExpDollar] $ + +# 563| [RegExpDollar] $ + +# 563| [RegExpConstant, RegExpNormalChar] X + +# 564| [RegExpConstant, RegExpNormalChar] / + +# 564| [RegExpSequence] /("[^"]*?"|[^"\s]+)+(?=X) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] / +#-----| 1 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ +#-----| 2 -> [RegExpPositiveLookahead] (?=X) + # 564| [RegExpGroup] ("[^"]*?"|[^"\s]+) #-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ @@ -6029,92 +6206,43 @@ redos_variants.swift: # 564| [RegExpCharacterClassEscape] \s -# 564| [RegExpPositiveLookahead] (?=\s*|\s*$) - -# 564| [RegExpCharacterClassEscape] \s - -# 564| [RegExpStar] \s* -#-----| 0 -> [RegExpCharacterClassEscape] \s - -# 564| [RegExpAlt] \s*|\s*$ -#-----| 0 -> [RegExpStar] \s* -#-----| 1 -> [RegExpSequence] \s*$ - -# 564| [RegExpCharacterClassEscape] \s - -# 564| [RegExpStar] \s* -#-----| 0 -> [RegExpCharacterClassEscape] \s - -# 564| [RegExpSequence] \s*$ -#-----| 0 -> [RegExpStar] \s* -#-----| 1 -> [RegExpDollar] $ - -# 564| [RegExpDollar] $ +# 564| [RegExpPositiveLookahead] (?=X) # 564| [RegExpConstant, RegExpNormalChar] X -# 565| [RegExpConstant, RegExpNormalChar] / +# 568| [RegExpCaret] \A -# 565| [RegExpSequence] /("[^"]*?"|[^"\s]+)+(?=X) -#-----| 0 -> [RegExpConstant, RegExpNormalChar] / -#-----| 1 -> [RegExpPlus] ("[^"]*?"|[^"\s]+)+ -#-----| 2 -> [RegExpPositiveLookahead] (?=X) - -# 565| [RegExpGroup] ("[^"]*?"|[^"\s]+) -#-----| 0 -> [RegExpAlt] "[^"]*?"|[^"\s]+ - -# 565| [RegExpPlus] ("[^"]*?"|[^"\s]+)+ -#-----| 0 -> [RegExpGroup] ("[^"]*?"|[^"\s]+) - -# 565| [RegExpConstant, RegExpNormalChar] " - -# 565| [RegExpSequence] "[^"]*?" -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " -#-----| 1 -> [RegExpStar] [^"]*? -#-----| 2 -> [RegExpConstant, RegExpNormalChar] " - -# 565| [RegExpAlt] "[^"]*?"|[^"\s]+ -#-----| 0 -> [RegExpSequence] "[^"]*?" -#-----| 1 -> [RegExpPlus] [^"\s]+ - -# 565| [RegExpCharacterClass] [^"] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " - -# 565| [RegExpStar] [^"]*? -#-----| 0 -> [RegExpCharacterClass] [^"] - -# 565| [RegExpConstant, RegExpNormalChar] " - -# 565| [RegExpConstant, RegExpNormalChar] " - -# 565| [RegExpCharacterClass] [^"\s] -#-----| 0 -> [RegExpConstant, RegExpNormalChar] " -#-----| 1 -> [RegExpCharacterClassEscape] \s - -# 565| [RegExpPlus] [^"\s]+ -#-----| 0 -> [RegExpCharacterClass] [^"\s] - -# 565| [RegExpConstant, RegExpNormalChar] " - -# 565| [RegExpCharacterClassEscape] \s - -# 565| [RegExpPositiveLookahead] (?=X) - -# 565| [RegExpConstant, RegExpNormalChar] X - -# 569| [RegExpCaret] \A - -# 569| [RegExpSequence] \A(\d|0)*x +# 568| [RegExpSequence] \A(\d|0)*x #-----| 0 -> [RegExpCaret] \A #-----| 1 -> [RegExpStar] (\d|0)* #-----| 2 -> [RegExpConstant, RegExpNormalChar] x +# 568| [RegExpGroup] (\d|0) +#-----| 0 -> [RegExpAlt] \d|0 + +# 568| [RegExpStar] (\d|0)* +#-----| 0 -> [RegExpGroup] (\d|0) + +# 568| [RegExpCharacterClassEscape] \d + +# 568| [RegExpAlt] \d|0 +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 0 + +# 568| [RegExpConstant, RegExpNormalChar] 0 + +# 568| [RegExpConstant, RegExpNormalChar] x + # 569| [RegExpGroup] (\d|0) #-----| 0 -> [RegExpAlt] \d|0 # 569| [RegExpStar] (\d|0)* #-----| 0 -> [RegExpGroup] (\d|0) +# 569| [RegExpSequence] (\d|0)*\Z +#-----| 0 -> [RegExpStar] (\d|0)* +#-----| 1 -> [RegExpDollar] \Z + # 569| [RegExpCharacterClassEscape] \d # 569| [RegExpAlt] \d|0 @@ -6123,7 +6251,14 @@ redos_variants.swift: # 569| [RegExpConstant, RegExpNormalChar] 0 -# 569| [RegExpConstant, RegExpNormalChar] x +# 569| [RegExpDollar] \Z + +# 570| [RegExpSpecialChar] \b + +# 570| [RegExpSequence] \b(\d|0)*x +#-----| 0 -> [RegExpSpecialChar] \b +#-----| 1 -> [RegExpStar] (\d|0)* +#-----| 2 -> [RegExpConstant, RegExpNormalChar] x # 570| [RegExpGroup] (\d|0) #-----| 0 -> [RegExpAlt] \d|0 @@ -6131,10 +6266,6 @@ redos_variants.swift: # 570| [RegExpStar] (\d|0)* #-----| 0 -> [RegExpGroup] (\d|0) -# 570| [RegExpSequence] (\d|0)*\Z -#-----| 0 -> [RegExpStar] (\d|0)* -#-----| 1 -> [RegExpDollar] \Z - # 570| [RegExpCharacterClassEscape] \d # 570| [RegExpAlt] \d|0 @@ -6143,30 +6274,20 @@ redos_variants.swift: # 570| [RegExpConstant, RegExpNormalChar] 0 -# 570| [RegExpDollar] \Z +# 570| [RegExpConstant, RegExpNormalChar] x -# 571| [RegExpSpecialChar] \b +# 573| [RegExpConstant, RegExpNormalChar] a -# 571| [RegExpSequence] \b(\d|0)*x -#-----| 0 -> [RegExpSpecialChar] \b -#-----| 1 -> [RegExpStar] (\d|0)* -#-----| 2 -> [RegExpConstant, RegExpNormalChar] x +# 573| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 571| [RegExpGroup] (\d|0) -#-----| 0 -> [RegExpAlt] \d|0 +# 573| [RegExpConstant, RegExpNormalChar] b -# 571| [RegExpStar] (\d|0)* -#-----| 0 -> [RegExpGroup] (\d|0) +# 574| [RegExpGroup] (a*) +#-----| 0 -> [RegExpStar] a* -# 571| [RegExpCharacterClassEscape] \d - -# 571| [RegExpAlt] \d|0 -#-----| 0 -> [RegExpCharacterClassEscape] \d -#-----| 1 -> [RegExpConstant, RegExpNormalChar] 0 - -# 571| [RegExpConstant, RegExpNormalChar] 0 - -# 571| [RegExpConstant, RegExpNormalChar] x +# 574| [RegExpStar] (a*)* +#-----| 0 -> [RegExpGroup] (a*) # 574| [RegExpConstant, RegExpNormalChar] a @@ -6175,12 +6296,6 @@ redos_variants.swift: # 574| [RegExpConstant, RegExpNormalChar] b -# 575| [RegExpGroup] (a*) -#-----| 0 -> [RegExpStar] a* - -# 575| [RegExpStar] (a*)* -#-----| 0 -> [RegExpGroup] (a*) - # 575| [RegExpConstant, RegExpNormalChar] a # 575| [RegExpStar] a* @@ -6188,27 +6303,20 @@ redos_variants.swift: # 575| [RegExpConstant, RegExpNormalChar] b -# 576| [RegExpConstant, RegExpNormalChar] a +# 579| [RegExpConstant, RegExpNormalChar] aa -# 576| [RegExpStar] a* -#-----| 0 -> [RegExpConstant, RegExpNormalChar] a - -# 576| [RegExpConstant, RegExpNormalChar] b - -# 580| [RegExpConstant, RegExpNormalChar] aa - -# 580| [RegExpAlt] aa|a* +# 579| [RegExpAlt] aa|a* #-----| 0 -> [RegExpConstant, RegExpNormalChar] aa #-----| 1 -> [RegExpStar] a* -# 580| [RegExpConstant, RegExpNormalChar] a +# 579| [RegExpConstant, RegExpNormalChar] a -# 580| [RegExpStar] a* +# 579| [RegExpStar] a* #-----| 0 -> [RegExpConstant, RegExpNormalChar] a -# 580| [RegExpConstant, RegExpNormalChar] b +# 579| [RegExpConstant, RegExpNormalChar] b -# 580| [RegExpConstant, RegExpNormalChar] c +# 579| [RegExpConstant, RegExpNormalChar] c regex.swift: # 103| [RegExpDot] . diff --git a/swift/ql/test/library-tests/regex/redos_variants.swift b/swift/ql/test/library-tests/regex/redos_variants.swift index 4c2b16626a7..d09a512b042 100644 --- a/swift/ql/test/library-tests/regex/redos_variants.swift +++ b/swift/ql/test/library-tests/regex/redos_variants.swift @@ -379,13 +379,12 @@ func myRegexpVariantsTests(myUrl: URL) throws { _ = try Regex(#"([^\\\]]+)*"#).firstMatch(in: tainted) // BAD - // TODO: QL evaluation times out (for test, at 5 minutes) - // times out: -// _ = try Regex(#"(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-"#).firstMatch(in: tainted) // $ redos-vulnerable= - // a simpler regex that times out: -// _ = try Regex(#"(\w*foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar)+"#).firstMatch(in: tainted) // $ redos-vulnerable= - // a simpler regerx that doesn't time out but is slow to evaluate: -// _ = try Regex(#"(\w*foobarfoobarfoobar)+"#).firstMatch(in: tainted) // $ redos-vulnerable= + _ = try Regex(#"(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-"#).firstMatch(in: tainted) // $ redos-vulnerable= + + // GOOD + // (these regexs explore a query performance issue we had at one point) + _ = try Regex(#"(\w*foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar)+"#).firstMatch(in: tainted) + _ = try Regex(#"(\w*foobarfoobarfoobar)+"#).firstMatch(in: tainted) // BAD (but cannot currently construct a prefix) // attack string: "aa" + "b" x lots + "!" From ba7cb8f4ae4b075a9a07e91a0091e3e6150df8d7 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 21 Jun 2023 17:54:52 -0400 Subject: [PATCH 261/364] C++: fix range analysis back edge detection for irreducible CFGs --- .../new/internal/semantic/SemanticSSA.qll | 15 ++++++++++++ .../library-tests/ir/range-analysis/test.cpp | 24 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll index 29580c2c507..65c0efec4aa 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll @@ -70,6 +70,21 @@ predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionP // Conservatively assume that every edge is a back edge if we don't have dominance information. ( phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or + trimmedReachable(phi.getBasicBlock(), edge.getOrigBlock()) or not edge.getOrigBlock().hasDominanceInformation() ) } + +private predicate trimmedReachable(SemBasicBlock b1, SemBasicBlock b2) { + b1 = b2 + or + exists(SemBasicBlock mid | + trimmedReachable(b1, mid) and + trimmedEdges(mid, b2) + ) +} + +private predicate trimmedEdges(SemBasicBlock pred, SemBasicBlock succ) { + pred.getASuccessor() = succ and + not succ.bbDominates(pred) +} diff --git a/cpp/ql/test/library-tests/ir/range-analysis/test.cpp b/cpp/ql/test/library-tests/ir/range-analysis/test.cpp index 95e6474124a..1e28d858b78 100644 --- a/cpp/ql/test/library-tests/ir/range-analysis/test.cpp +++ b/cpp/ql/test/library-tests/ir/range-analysis/test.cpp @@ -70,3 +70,27 @@ int f4(int x) { } } } + +// No interesting ranges to check here - this irreducible CFG caused an infinite loop due to back edge detection +void gotoLoop(bool b1, bool b2) +{ + int j; + + if (b1) + return; + + if (!b2) + { + for (j = 0; j < 10; ++j) + { + goto main_decode_loop; + } + } + else + { + for (j = 0; j < 10; ++j) + { + main_decode_loop: + } + } +} \ No newline at end of file From ade4d68793d40d1b4e3daf7bc17bcc0f7a803879 Mon Sep 17 00:00:00 2001 From: Alex Denisov Date: Thu, 22 Jun 2023 09:26:29 +0200 Subject: [PATCH 262/364] Swift: bump C++ version in CMake --- swift/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/CMakeLists.txt b/swift/CMakeLists.txt index ba4a30d5c4a..2b44cc58993 100644 --- a/swift/CMakeLists.txt +++ b/swift/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.21) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_C_COMPILER clang) From 36f980f4bf4096e0005c0099c85edcc69f6f0e26 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 22 Jun 2023 09:46:02 +0100 Subject: [PATCH 263/364] Swift: Hide summarized nodes from paths. --- swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll index c0f01a67df3..6b830982d6f 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll @@ -282,7 +282,7 @@ private predicate hasPatternNode(PatternCfgNode n, Pattern p) { import Cached /** Holds if `n` should be hidden from path explanations. */ -predicate nodeIsHidden(Node n) { none() } +predicate nodeIsHidden(Node n) { n instanceof FlowSummaryNode } private module ParameterNodes { abstract class ParameterNodeImpl extends NodeImpl { From c50a0419e2c9145f40a2ad0de3961b2bee48e183 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 22 Jun 2023 09:46:10 +0100 Subject: [PATCH 264/364] Swift: Accept test changes. --- .../dataflow/dataflow/DataFlow.expected | 16 -------------- .../CWE-079/UnsafeWebViewFetch.expected | 21 ------------------- .../Security/CWE-089/SqlInjection.expected | 10 --------- .../Security/CWE-094/UnsafeJsEval.expected | 20 ------------------ .../StaticInitializationVector.expected | 11 ---------- .../CWE-134/UncontrolledFormatString.expected | 11 ---------- .../CWE-311/CleartextTransmission.expected | 5 ----- .../CWE-321/HardcodedEncryptionKey.expected | 10 --------- .../Security/CWE-760/ConstantSalt.expected | 7 ------- 9 files changed, 111 deletions(-) diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected index b725e5e7298..bebfd102871 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected @@ -1,6 +1,4 @@ edges -| file://:0:0:0:0 | [summary param] this in signum() | file://:0:0:0:0 | [summary] to write: return (return) in signum() | -| file://:0:0:0:0 | [summary param] this in signum() [some:0] | file://:0:0:0:0 | [summary] to write: return (return) in signum() [some:0] | | file://:0:0:0:0 | self [a, x] | file://:0:0:0:0 | .a [x] | | file://:0:0:0:0 | self [str] | file://:0:0:0:0 | .str | | file://:0:0:0:0 | self [x, some:0] | file://:0:0:0:0 | .x [some:0] | @@ -122,9 +120,7 @@ edges | test.swift:263:13:263:28 | call to optionalSource() [some:0] | test.swift:298:11:298:15 | let ...? [some:0] | | test.swift:263:13:263:28 | call to optionalSource() [some:0] | test.swift:306:13:306:24 | .some(...) [some:0] | | test.swift:263:13:263:28 | call to optionalSource() [some:0] | test.swift:314:10:314:21 | .some(...) [some:0] | -| test.swift:270:15:270:22 | call to source() | file://:0:0:0:0 | [summary param] this in signum() | | test.swift:270:15:270:22 | call to source() | test.swift:270:15:270:31 | call to signum() | -| test.swift:271:15:271:16 | ...? | file://:0:0:0:0 | [summary param] this in signum() | | test.swift:271:15:271:16 | ...? | test.swift:271:15:271:25 | call to signum() | | test.swift:271:15:271:25 | call to signum() | test.swift:271:15:271:25 | OptionalEvaluationExpr | | test.swift:280:31:280:38 | call to source() | test.swift:280:15:280:38 | ... ? ... : ... | @@ -133,15 +129,12 @@ edges | test.swift:284:12:284:12 | z | test.swift:285:19:285:19 | z | | test.swift:291:8:291:12 | let ...? [some:0] | test.swift:291:12:291:12 | z | | test.swift:291:12:291:12 | z | test.swift:292:19:292:19 | z | -| test.swift:291:16:291:17 | ...? | file://:0:0:0:0 | [summary param] this in signum() | | test.swift:291:16:291:17 | ...? | test.swift:291:16:291:26 | call to signum() | -| test.swift:291:16:291:17 | ...? [some:0] | file://:0:0:0:0 | [summary param] this in signum() [some:0] | | test.swift:291:16:291:17 | ...? [some:0] | test.swift:291:16:291:26 | call to signum() [some:0] | | test.swift:291:16:291:26 | call to signum() | test.swift:291:16:291:26 | call to signum() [some:0] | | test.swift:291:16:291:26 | call to signum() [some:0] | test.swift:291:8:291:12 | let ...? [some:0] | | test.swift:298:11:298:15 | let ...? [some:0] | test.swift:298:15:298:15 | z1 | | test.swift:298:15:298:15 | z1 | test.swift:300:15:300:15 | z1 | -| test.swift:303:15:303:16 | ...! | file://:0:0:0:0 | [summary param] this in signum() | | test.swift:303:15:303:16 | ...! | test.swift:303:15:303:25 | call to signum() | | test.swift:306:13:306:24 | .some(...) [some:0] | test.swift:306:23:306:23 | z | | test.swift:306:23:306:23 | z | test.swift:307:19:307:19 | z | @@ -283,10 +276,6 @@ nodes | file://:0:0:0:0 | .x [some:0] | semmle.label | .x [some:0] | | file://:0:0:0:0 | [post] self [x, some:0] | semmle.label | [post] self [x, some:0] | | file://:0:0:0:0 | [post] self [x] | semmle.label | [post] self [x] | -| file://:0:0:0:0 | [summary param] this in signum() | semmle.label | [summary param] this in signum() | -| file://:0:0:0:0 | [summary param] this in signum() [some:0] | semmle.label | [summary param] this in signum() [some:0] | -| file://:0:0:0:0 | [summary] to write: return (return) in signum() | semmle.label | [summary] to write: return (return) in signum() | -| file://:0:0:0:0 | [summary] to write: return (return) in signum() [some:0] | semmle.label | [summary] to write: return (return) in signum() [some:0] | | file://:0:0:0:0 | self [a, x] | semmle.label | self [a, x] | | file://:0:0:0:0 | self [str] | semmle.label | self [str] | | file://:0:0:0:0 | self [x, some:0] | semmle.label | self [x, some:0] | @@ -599,11 +588,6 @@ subpaths | test.swift:218:11:218:18 | call to source() | test.swift:169:12:169:22 | value | test.swift:170:5:170:5 | [post] self [x] | test.swift:218:3:218:5 | [post] getter for .a [x] | | test.swift:219:13:219:13 | b [a, x] | test.swift:185:7:185:7 | self [a, x] | file://:0:0:0:0 | .a [x] | test.swift:219:13:219:15 | .a [x] | | test.swift:219:13:219:15 | .a [x] | test.swift:163:7:163:7 | self [x] | file://:0:0:0:0 | .x | test.swift:219:13:219:17 | .x | -| test.swift:270:15:270:22 | call to source() | file://:0:0:0:0 | [summary param] this in signum() | file://:0:0:0:0 | [summary] to write: return (return) in signum() | test.swift:270:15:270:31 | call to signum() | -| test.swift:271:15:271:16 | ...? | file://:0:0:0:0 | [summary param] this in signum() | file://:0:0:0:0 | [summary] to write: return (return) in signum() | test.swift:271:15:271:25 | call to signum() | -| test.swift:291:16:291:17 | ...? | file://:0:0:0:0 | [summary param] this in signum() | file://:0:0:0:0 | [summary] to write: return (return) in signum() | test.swift:291:16:291:26 | call to signum() | -| test.swift:291:16:291:17 | ...? [some:0] | file://:0:0:0:0 | [summary param] this in signum() [some:0] | file://:0:0:0:0 | [summary] to write: return (return) in signum() [some:0] | test.swift:291:16:291:26 | call to signum() [some:0] | -| test.swift:303:15:303:16 | ...! | file://:0:0:0:0 | [summary param] this in signum() | file://:0:0:0:0 | [summary] to write: return (return) in signum() | test.swift:303:15:303:25 | call to signum() | | test.swift:515:12:515:12 | x [some:0] | test.swift:509:9:509:9 | value [some:0] | file://:0:0:0:0 | [post] self [x, some:0] | test.swift:515:5:515:5 | [post] cx [x, some:0] | | test.swift:519:20:519:20 | cx [x, some:0] | test.swift:509:9:509:9 | self [x, some:0] | file://:0:0:0:0 | .x [some:0] | test.swift:519:20:519:23 | .x [some:0] | | test.swift:543:20:543:28 | call to source3() | test.swift:536:10:536:13 | s | test.swift:537:7:537:7 | [post] self [str] | test.swift:543:7:543:7 | [post] self [str] | diff --git a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected index b21ed3b030c..e7c8443bfa2 100644 --- a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected +++ b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected @@ -1,7 +1,4 @@ edges -| UnsafeWebViewFetch.swift:10:2:10:25 | [summary param] 0 in URL.init(string:) | UnsafeWebViewFetch.swift:10:2:10:25 | [summary] to write: return (return) in URL.init(string:) | -| UnsafeWebViewFetch.swift:11:2:11:43 | [summary param] 1 in URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:11:2:11:43 | [summary] to write: return (return) in URL.init(string:relativeTo:) | -| UnsafeWebViewFetch.swift:43:5:43:29 | [summary param] 0 in Data.init(_:) | UnsafeWebViewFetch.swift:43:5:43:29 | [summary] to write: return (return) in Data.init(_:) | | UnsafeWebViewFetch.swift:94:10:94:37 | try ... | UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() | | UnsafeWebViewFetch.swift:94:10:94:37 | try ... | UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | | UnsafeWebViewFetch.swift:94:10:94:37 | try ... | UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() | @@ -25,15 +22,12 @@ edges | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:139:48:139:57 | ...! | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:153:85:153:94 | ...! | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:154:86:154:95 | ...! | -| UnsafeWebViewFetch.swift:131:30:131:30 | remoteString | UnsafeWebViewFetch.swift:10:2:10:25 | [summary param] 0 in URL.init(string:) | | UnsafeWebViewFetch.swift:131:30:131:30 | remoteString | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | | UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:140:47:140:57 | ...! | | UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:141:48:141:58 | ...! | -| UnsafeWebViewFetch.swift:132:52:132:52 | remoteURL | UnsafeWebViewFetch.swift:11:2:11:43 | [summary param] 1 in URL.init(string:relativeTo:) | | UnsafeWebViewFetch.swift:132:52:132:52 | remoteURL | UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) | | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:152:15:152:15 | remoteData | | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | -| UnsafeWebViewFetch.swift:150:24:150:37 | .utf8 | UnsafeWebViewFetch.swift:43:5:43:29 | [summary param] 0 in Data.init(_:) | | UnsafeWebViewFetch.swift:150:24:150:37 | .utf8 | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | | UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | | UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:171:25:171:51 | ... .+(_:_:) ... | @@ -49,25 +43,16 @@ edges | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:186:48:186:57 | ...! | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:200:90:200:99 | ...! | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:201:91:201:100 | ...! | -| UnsafeWebViewFetch.swift:178:30:178:30 | remoteString | UnsafeWebViewFetch.swift:10:2:10:25 | [summary param] 0 in URL.init(string:) | | UnsafeWebViewFetch.swift:178:30:178:30 | remoteString | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | | UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:187:47:187:57 | ...! | | UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:188:48:188:58 | ...! | -| UnsafeWebViewFetch.swift:179:52:179:52 | remoteURL | UnsafeWebViewFetch.swift:11:2:11:43 | [summary param] 1 in URL.init(string:relativeTo:) | | UnsafeWebViewFetch.swift:179:52:179:52 | remoteURL | UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) | | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:199:15:199:15 | remoteData | | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | -| UnsafeWebViewFetch.swift:197:24:197:37 | .utf8 | UnsafeWebViewFetch.swift:43:5:43:29 | [summary param] 0 in Data.init(_:) | | UnsafeWebViewFetch.swift:197:24:197:37 | .utf8 | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | | UnsafeWebViewFetch.swift:206:17:206:31 | call to getRemoteData() | UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | | UnsafeWebViewFetch.swift:206:17:206:31 | call to getRemoteData() | UnsafeWebViewFetch.swift:211:25:211:25 | htmlData | nodes -| UnsafeWebViewFetch.swift:10:2:10:25 | [summary param] 0 in URL.init(string:) | semmle.label | [summary param] 0 in URL.init(string:) | -| UnsafeWebViewFetch.swift:10:2:10:25 | [summary] to write: return (return) in URL.init(string:) | semmle.label | [summary] to write: return (return) in URL.init(string:) | -| UnsafeWebViewFetch.swift:11:2:11:43 | [summary param] 1 in URL.init(string:relativeTo:) | semmle.label | [summary param] 1 in URL.init(string:relativeTo:) | -| UnsafeWebViewFetch.swift:11:2:11:43 | [summary] to write: return (return) in URL.init(string:relativeTo:) | semmle.label | [summary] to write: return (return) in URL.init(string:relativeTo:) | -| UnsafeWebViewFetch.swift:43:5:43:29 | [summary param] 0 in Data.init(_:) | semmle.label | [summary param] 0 in Data.init(_:) | -| UnsafeWebViewFetch.swift:43:5:43:29 | [summary] to write: return (return) in Data.init(_:) | semmle.label | [summary] to write: return (return) in Data.init(_:) | | UnsafeWebViewFetch.swift:94:10:94:37 | try ... | semmle.label | try ... | | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | | UnsafeWebViewFetch.swift:103:25:103:84 | try! ... | semmle.label | try! ... | @@ -126,12 +111,6 @@ nodes | UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | semmle.label | htmlData | | UnsafeWebViewFetch.swift:211:25:211:25 | htmlData | semmle.label | htmlData | subpaths -| UnsafeWebViewFetch.swift:131:30:131:30 | remoteString | UnsafeWebViewFetch.swift:10:2:10:25 | [summary param] 0 in URL.init(string:) | UnsafeWebViewFetch.swift:10:2:10:25 | [summary] to write: return (return) in URL.init(string:) | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | -| UnsafeWebViewFetch.swift:132:52:132:52 | remoteURL | UnsafeWebViewFetch.swift:11:2:11:43 | [summary param] 1 in URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:11:2:11:43 | [summary] to write: return (return) in URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) | -| UnsafeWebViewFetch.swift:150:24:150:37 | .utf8 | UnsafeWebViewFetch.swift:43:5:43:29 | [summary param] 0 in Data.init(_:) | UnsafeWebViewFetch.swift:43:5:43:29 | [summary] to write: return (return) in Data.init(_:) | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | -| UnsafeWebViewFetch.swift:178:30:178:30 | remoteString | UnsafeWebViewFetch.swift:10:2:10:25 | [summary param] 0 in URL.init(string:) | UnsafeWebViewFetch.swift:10:2:10:25 | [summary] to write: return (return) in URL.init(string:) | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | -| UnsafeWebViewFetch.swift:179:52:179:52 | remoteURL | UnsafeWebViewFetch.swift:11:2:11:43 | [summary param] 1 in URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:11:2:11:43 | [summary] to write: return (return) in URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) | -| UnsafeWebViewFetch.swift:197:24:197:37 | .utf8 | UnsafeWebViewFetch.swift:43:5:43:29 | [summary param] 0 in Data.init(_:) | UnsafeWebViewFetch.swift:43:5:43:29 | [summary] to write: return (return) in Data.init(_:) | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | #select | UnsafeWebViewFetch.swift:103:25:103:84 | try! ... | UnsafeWebViewFetch.swift:103:30:103:84 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:103:25:103:84 | try! ... | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:106:25:106:25 | data | UnsafeWebViewFetch.swift:105:18:105:72 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:106:25:106:25 | data | Tainted data is used in a WebView fetch without restricting the base URL. | diff --git a/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.expected b/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.expected index 7c5466939f2..a4617e9b811 100644 --- a/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.expected +++ b/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.expected @@ -97,8 +97,6 @@ edges | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | SQLite.swift:117:16:117:16 | unsafeQuery1 | | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | SQLite.swift:119:16:119:16 | unsafeQuery1 | | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | SQLite.swift:132:20:132:20 | remoteString | -| sqlite3_c_api.swift:15:2:15:71 | [summary param] this in copyBytes(to:count:) | sqlite3_c_api.swift:15:2:15:71 | [summary] to write: argument 0 in copyBytes(to:count:) | -| sqlite3_c_api.swift:37:2:37:103 | [summary param] this in data(using:allowLossyConversion:) | sqlite3_c_api.swift:37:2:37:103 | [summary] to write: return (return) in data(using:allowLossyConversion:) | | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:133:33:133:33 | unsafeQuery1 | | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:134:33:134:33 | unsafeQuery2 | | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:135:33:135:33 | unsafeQuery3 | @@ -106,10 +104,8 @@ edges | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:175:29:175:29 | unsafeQuery3 | | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:183:29:183:29 | unsafeQuery3 | | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:189:13:189:13 | unsafeQuery3 | -| sqlite3_c_api.swift:189:13:189:13 | unsafeQuery3 | sqlite3_c_api.swift:37:2:37:103 | [summary param] this in data(using:allowLossyConversion:) | | sqlite3_c_api.swift:189:13:189:13 | unsafeQuery3 | sqlite3_c_api.swift:189:13:189:58 | call to data(using:allowLossyConversion:) | | sqlite3_c_api.swift:189:13:189:58 | call to data(using:allowLossyConversion:) | sqlite3_c_api.swift:190:2:190:2 | data | -| sqlite3_c_api.swift:190:2:190:2 | data | sqlite3_c_api.swift:15:2:15:71 | [summary param] this in copyBytes(to:count:) | | sqlite3_c_api.swift:190:2:190:2 | data | sqlite3_c_api.swift:190:21:190:21 | [post] buffer | | sqlite3_c_api.swift:190:21:190:21 | [post] buffer | sqlite3_c_api.swift:194:28:194:28 | buffer | | sqlite3_c_api.swift:190:21:190:21 | [post] buffer | sqlite3_c_api.swift:202:31:202:31 | buffer | @@ -226,10 +222,6 @@ nodes | SQLite.swift:117:16:117:16 | unsafeQuery1 | semmle.label | unsafeQuery1 | | SQLite.swift:119:16:119:16 | unsafeQuery1 | semmle.label | unsafeQuery1 | | SQLite.swift:132:20:132:20 | remoteString | semmle.label | remoteString | -| sqlite3_c_api.swift:15:2:15:71 | [summary param] this in copyBytes(to:count:) | semmle.label | [summary param] this in copyBytes(to:count:) | -| sqlite3_c_api.swift:15:2:15:71 | [summary] to write: argument 0 in copyBytes(to:count:) | semmle.label | [summary] to write: argument 0 in copyBytes(to:count:) | -| sqlite3_c_api.swift:37:2:37:103 | [summary param] this in data(using:allowLossyConversion:) | semmle.label | [summary param] this in data(using:allowLossyConversion:) | -| sqlite3_c_api.swift:37:2:37:103 | [summary] to write: return (return) in data(using:allowLossyConversion:) | semmle.label | [summary] to write: return (return) in data(using:allowLossyConversion:) | | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | | sqlite3_c_api.swift:133:33:133:33 | unsafeQuery1 | semmle.label | unsafeQuery1 | | sqlite3_c_api.swift:134:33:134:33 | unsafeQuery2 | semmle.label | unsafeQuery2 | @@ -245,8 +237,6 @@ nodes | sqlite3_c_api.swift:202:31:202:31 | buffer | semmle.label | buffer | | sqlite3_c_api.swift:210:31:210:31 | buffer | semmle.label | buffer | subpaths -| sqlite3_c_api.swift:189:13:189:13 | unsafeQuery3 | sqlite3_c_api.swift:37:2:37:103 | [summary param] this in data(using:allowLossyConversion:) | sqlite3_c_api.swift:37:2:37:103 | [summary] to write: return (return) in data(using:allowLossyConversion:) | sqlite3_c_api.swift:189:13:189:58 | call to data(using:allowLossyConversion:) | -| sqlite3_c_api.swift:190:2:190:2 | data | sqlite3_c_api.swift:15:2:15:71 | [summary param] this in copyBytes(to:count:) | sqlite3_c_api.swift:15:2:15:71 | [summary] to write: argument 0 in copyBytes(to:count:) | sqlite3_c_api.swift:190:21:190:21 | [post] buffer | #select | GRDB.swift:106:41:106:41 | remoteString | GRDB.swift:104:25:104:79 | call to String.init(contentsOf:) | GRDB.swift:106:41:106:41 | remoteString | This query depends on a $@. | GRDB.swift:104:25:104:79 | call to String.init(contentsOf:) | user-provided value | | GRDB.swift:108:41:108:41 | remoteString | GRDB.swift:104:25:104:79 | call to String.init(contentsOf:) | GRDB.swift:108:41:108:41 | remoteString | This query depends on a $@. | GRDB.swift:104:25:104:79 | call to String.init(contentsOf:) | user-provided value | diff --git a/swift/ql/test/query-tests/Security/CWE-094/UnsafeJsEval.expected b/swift/ql/test/query-tests/Security/CWE-094/UnsafeJsEval.expected index de1c23c52a8..3e810179bcf 100644 --- a/swift/ql/test/query-tests/Security/CWE-094/UnsafeJsEval.expected +++ b/swift/ql/test/query-tests/Security/CWE-094/UnsafeJsEval.expected @@ -1,8 +1,5 @@ edges -| UnsafeJsEval.swift:69:2:73:5 | [summary param] 0 in WKUserScript.init(source:injectionTime:forMainFrameOnly:) | UnsafeJsEval.swift:69:2:73:5 | [summary] to write: return (return) in WKUserScript.init(source:injectionTime:forMainFrameOnly:) | -| UnsafeJsEval.swift:75:2:80:5 | [summary param] 0 in WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | UnsafeJsEval.swift:75:2:80:5 | [summary] to write: return (return) in WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | | UnsafeJsEval.swift:124:21:124:42 | string | UnsafeJsEval.swift:124:70:124:70 | string | -| UnsafeJsEval.swift:144:5:144:29 | [summary param] 0 in Data.init(_:) | UnsafeJsEval.swift:144:5:144:29 | [summary] to write: return (return) in Data.init(_:) | | UnsafeJsEval.swift:165:10:165:37 | try ... | UnsafeJsEval.swift:201:21:201:35 | call to getRemoteData() | | UnsafeJsEval.swift:165:14:165:37 | call to String.init(contentsOf:) | UnsafeJsEval.swift:165:10:165:37 | try ... | | UnsafeJsEval.swift:201:21:201:35 | call to getRemoteData() | UnsafeJsEval.swift:205:7:205:7 | remoteString | @@ -28,7 +25,6 @@ edges | UnsafeJsEval.swift:208:7:208:39 | ... .+(_:_:) ... | UnsafeJsEval.swift:285:13:285:13 | string | | UnsafeJsEval.swift:208:7:208:39 | ... .+(_:_:) ... | UnsafeJsEval.swift:299:13:299:13 | string | | UnsafeJsEval.swift:211:19:211:41 | call to Data.init(_:) | UnsafeJsEval.swift:214:24:214:24 | remoteData | -| UnsafeJsEval.swift:211:24:211:37 | .utf8 | UnsafeJsEval.swift:144:5:144:29 | [summary param] 0 in Data.init(_:) | | UnsafeJsEval.swift:211:24:211:37 | .utf8 | UnsafeJsEval.swift:211:19:211:41 | call to Data.init(_:) | | UnsafeJsEval.swift:214:7:214:49 | call to String.init(decoding:as:) | UnsafeJsEval.swift:265:13:265:13 | string | | UnsafeJsEval.swift:214:7:214:49 | call to String.init(decoding:as:) | UnsafeJsEval.swift:268:13:268:13 | string | @@ -37,12 +33,9 @@ edges | UnsafeJsEval.swift:214:7:214:49 | call to String.init(decoding:as:) | UnsafeJsEval.swift:285:13:285:13 | string | | UnsafeJsEval.swift:214:7:214:49 | call to String.init(decoding:as:) | UnsafeJsEval.swift:299:13:299:13 | string | | UnsafeJsEval.swift:214:24:214:24 | remoteData | UnsafeJsEval.swift:214:7:214:49 | call to String.init(decoding:as:) | -| UnsafeJsEval.swift:214:24:214:24 | remoteData | file://:0:0:0:0 | [summary param] 0 in String.init(decoding:as:) | | UnsafeJsEval.swift:265:13:265:13 | string | UnsafeJsEval.swift:266:43:266:43 | string | -| UnsafeJsEval.swift:266:43:266:43 | string | UnsafeJsEval.swift:69:2:73:5 | [summary param] 0 in WKUserScript.init(source:injectionTime:forMainFrameOnly:) | | UnsafeJsEval.swift:266:43:266:43 | string | UnsafeJsEval.swift:266:22:266:107 | call to WKUserScript.init(source:injectionTime:forMainFrameOnly:) | | UnsafeJsEval.swift:268:13:268:13 | string | UnsafeJsEval.swift:269:43:269:43 | string | -| UnsafeJsEval.swift:269:43:269:43 | string | UnsafeJsEval.swift:75:2:80:5 | [summary param] 0 in WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | | UnsafeJsEval.swift:269:43:269:43 | string | UnsafeJsEval.swift:269:22:269:124 | call to WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | | UnsafeJsEval.swift:276:13:276:13 | string | UnsafeJsEval.swift:277:26:277:26 | string | | UnsafeJsEval.swift:279:13:279:13 | string | UnsafeJsEval.swift:280:26:280:26 | string | @@ -63,16 +56,9 @@ edges | UnsafeJsEval.swift:301:31:301:84 | call to JSStringCreateWithUTF8CString(_:) | UnsafeJsEval.swift:301:16:301:85 | call to JSStringRetain(_:) | | UnsafeJsEval.swift:301:31:301:84 | call to JSStringCreateWithUTF8CString(_:) | UnsafeJsEval.swift:305:17:305:17 | jsstr | | UnsafeJsEval.swift:318:24:318:87 | call to String.init(contentsOf:) | UnsafeJsEval.swift:320:44:320:74 | ... .+(_:_:) ... | -| file://:0:0:0:0 | [summary param] 0 in String.init(decoding:as:) | file://:0:0:0:0 | [summary] to write: return (return) in String.init(decoding:as:) | nodes -| UnsafeJsEval.swift:69:2:73:5 | [summary param] 0 in WKUserScript.init(source:injectionTime:forMainFrameOnly:) | semmle.label | [summary param] 0 in WKUserScript.init(source:injectionTime:forMainFrameOnly:) | -| UnsafeJsEval.swift:69:2:73:5 | [summary] to write: return (return) in WKUserScript.init(source:injectionTime:forMainFrameOnly:) | semmle.label | [summary] to write: return (return) in WKUserScript.init(source:injectionTime:forMainFrameOnly:) | -| UnsafeJsEval.swift:75:2:80:5 | [summary param] 0 in WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | semmle.label | [summary param] 0 in WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | -| UnsafeJsEval.swift:75:2:80:5 | [summary] to write: return (return) in WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | semmle.label | [summary] to write: return (return) in WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | | UnsafeJsEval.swift:124:21:124:42 | string | semmle.label | string | | UnsafeJsEval.swift:124:70:124:70 | string | semmle.label | string | -| UnsafeJsEval.swift:144:5:144:29 | [summary param] 0 in Data.init(_:) | semmle.label | [summary param] 0 in Data.init(_:) | -| UnsafeJsEval.swift:144:5:144:29 | [summary] to write: return (return) in Data.init(_:) | semmle.label | [summary] to write: return (return) in Data.init(_:) | | UnsafeJsEval.swift:165:10:165:37 | try ... | semmle.label | try ... | | UnsafeJsEval.swift:165:14:165:37 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | | UnsafeJsEval.swift:201:21:201:35 | call to getRemoteData() | semmle.label | call to getRemoteData() | @@ -108,13 +94,7 @@ nodes | UnsafeJsEval.swift:305:17:305:17 | jsstr | semmle.label | jsstr | | UnsafeJsEval.swift:318:24:318:87 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | | UnsafeJsEval.swift:320:44:320:74 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | -| file://:0:0:0:0 | [summary param] 0 in String.init(decoding:as:) | semmle.label | [summary param] 0 in String.init(decoding:as:) | -| file://:0:0:0:0 | [summary] to write: return (return) in String.init(decoding:as:) | semmle.label | [summary] to write: return (return) in String.init(decoding:as:) | subpaths -| UnsafeJsEval.swift:211:24:211:37 | .utf8 | UnsafeJsEval.swift:144:5:144:29 | [summary param] 0 in Data.init(_:) | UnsafeJsEval.swift:144:5:144:29 | [summary] to write: return (return) in Data.init(_:) | UnsafeJsEval.swift:211:19:211:41 | call to Data.init(_:) | -| UnsafeJsEval.swift:214:24:214:24 | remoteData | file://:0:0:0:0 | [summary param] 0 in String.init(decoding:as:) | file://:0:0:0:0 | [summary] to write: return (return) in String.init(decoding:as:) | UnsafeJsEval.swift:214:7:214:49 | call to String.init(decoding:as:) | -| UnsafeJsEval.swift:266:43:266:43 | string | UnsafeJsEval.swift:69:2:73:5 | [summary param] 0 in WKUserScript.init(source:injectionTime:forMainFrameOnly:) | UnsafeJsEval.swift:69:2:73:5 | [summary] to write: return (return) in WKUserScript.init(source:injectionTime:forMainFrameOnly:) | UnsafeJsEval.swift:266:22:266:107 | call to WKUserScript.init(source:injectionTime:forMainFrameOnly:) | -| UnsafeJsEval.swift:269:43:269:43 | string | UnsafeJsEval.swift:75:2:80:5 | [summary param] 0 in WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | UnsafeJsEval.swift:75:2:80:5 | [summary] to write: return (return) in WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | UnsafeJsEval.swift:269:22:269:124 | call to WKUserScript.init(source:injectionTime:forMainFrameOnly:in:) | | UnsafeJsEval.swift:287:31:287:97 | call to JSStringCreateWithCharacters(_:_:) | UnsafeJsEval.swift:124:21:124:42 | string | UnsafeJsEval.swift:124:70:124:70 | string | UnsafeJsEval.swift:287:16:287:98 | call to JSStringRetain(_:) | | UnsafeJsEval.swift:301:31:301:84 | call to JSStringCreateWithUTF8CString(_:) | UnsafeJsEval.swift:124:21:124:42 | string | UnsafeJsEval.swift:124:70:124:70 | string | UnsafeJsEval.swift:301:16:301:85 | call to JSStringRetain(_:) | #select diff --git a/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.expected b/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.expected index aa6cf49411c..848ce4937ae 100644 --- a/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.expected +++ b/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.expected @@ -1,20 +1,15 @@ edges -| rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | | rncryptor.swift:60:19:60:25 | call to Data.init(_:) | rncryptor.swift:68:104:68:104 | myConstIV1 | | rncryptor.swift:60:19:60:25 | call to Data.init(_:) | rncryptor.swift:77:125:77:125 | myConstIV1 | -| rncryptor.swift:60:24:60:24 | 0 | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | | rncryptor.swift:60:24:60:24 | 0 | rncryptor.swift:60:19:60:25 | call to Data.init(_:) | | rncryptor.swift:61:19:61:27 | call to Data.init(_:) | rncryptor.swift:70:104:70:104 | myConstIV2 | | rncryptor.swift:61:19:61:27 | call to Data.init(_:) | rncryptor.swift:79:133:79:133 | myConstIV2 | -| rncryptor.swift:61:24:61:24 | 123 | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | | rncryptor.swift:61:24:61:24 | 123 | rncryptor.swift:61:19:61:27 | call to Data.init(_:) | | rncryptor.swift:62:19:62:35 | call to Data.init(_:) | rncryptor.swift:72:84:72:84 | myConstIV3 | | rncryptor.swift:62:19:62:35 | call to Data.init(_:) | rncryptor.swift:81:105:81:105 | myConstIV3 | -| rncryptor.swift:62:24:62:34 | [...] | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | | rncryptor.swift:62:24:62:34 | [...] | rncryptor.swift:62:19:62:35 | call to Data.init(_:) | | rncryptor.swift:63:19:63:28 | call to Data.init(_:) | rncryptor.swift:74:84:74:84 | myConstIV4 | | rncryptor.swift:63:19:63:28 | call to Data.init(_:) | rncryptor.swift:83:113:83:113 | myConstIV4 | -| rncryptor.swift:63:24:63:24 | iv | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | | rncryptor.swift:63:24:63:24 | iv | rncryptor.swift:63:19:63:28 | call to Data.init(_:) | | test.swift:53:19:53:34 | iv | test.swift:54:17:54:17 | iv | | test.swift:85:3:85:3 | this string is constant | test.swift:101:17:101:35 | call to getConstantString() | @@ -40,8 +35,6 @@ edges | test.swift:101:17:101:35 | call to getConstantString() | test.swift:130:39:130:39 | ivString | | test.swift:147:22:147:22 | iv | test.swift:53:19:53:34 | iv | nodes -| rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | semmle.label | [summary param] 0 in Data.init(_:) | -| rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | semmle.label | [summary] to write: return (return) in Data.init(_:) | | rncryptor.swift:60:19:60:25 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | | rncryptor.swift:60:24:60:24 | 0 | semmle.label | 0 | | rncryptor.swift:61:19:61:27 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | @@ -84,10 +77,6 @@ nodes | test.swift:167:22:167:22 | iv | semmle.label | iv | | test.swift:168:22:168:22 | iv | semmle.label | iv | subpaths -| rncryptor.swift:60:24:60:24 | 0 | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | rncryptor.swift:60:19:60:25 | call to Data.init(_:) | -| rncryptor.swift:61:24:61:24 | 123 | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | rncryptor.swift:61:19:61:27 | call to Data.init(_:) | -| rncryptor.swift:62:24:62:34 | [...] | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | rncryptor.swift:62:19:62:35 | call to Data.init(_:) | -| rncryptor.swift:63:24:63:24 | iv | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | rncryptor.swift:63:19:63:28 | call to Data.init(_:) | #select | rncryptor.swift:68:104:68:104 | myConstIV1 | rncryptor.swift:60:24:60:24 | 0 | rncryptor.swift:68:104:68:104 | myConstIV1 | The static value '0' is used as an initialization vector for encryption. | | rncryptor.swift:70:104:70:104 | myConstIV2 | rncryptor.swift:61:24:61:24 | 123 | rncryptor.swift:70:104:70:104 | myConstIV2 | The static value '123' is used as an initialization vector for encryption. | diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected index dd2c4f66f74..3a2d4eb80c6 100644 --- a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected +++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected @@ -1,5 +1,4 @@ edges -| UncontrolledFormatString.swift:30:5:30:35 | [summary param] 0 in NSString.init(string:) | UncontrolledFormatString.swift:30:5:30:35 | [summary] to write: return (return) in NSString.init(string:) | | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | UncontrolledFormatString.swift:70:28:70:28 | tainted | | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | UncontrolledFormatString.swift:73:28:73:28 | tainted | | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | UncontrolledFormatString.swift:74:28:74:28 | tainted | @@ -13,17 +12,11 @@ edges | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | UncontrolledFormatString.swift:85:72:85:72 | tainted | | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | UncontrolledFormatString.swift:88:11:88:11 | tainted | | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | UncontrolledFormatString.swift:91:61:91:61 | tainted | -| UncontrolledFormatString.swift:81:47:81:47 | tainted | UncontrolledFormatString.swift:30:5:30:35 | [summary param] 0 in NSString.init(string:) | | UncontrolledFormatString.swift:81:47:81:47 | tainted | UncontrolledFormatString.swift:81:30:81:54 | call to NSString.init(string:) | -| UncontrolledFormatString.swift:82:65:82:65 | tainted | UncontrolledFormatString.swift:30:5:30:35 | [summary param] 0 in NSString.init(string:) | | UncontrolledFormatString.swift:82:65:82:65 | tainted | UncontrolledFormatString.swift:82:48:82:72 | call to NSString.init(string:) | -| UncontrolledFormatString.swift:84:54:84:54 | tainted | UncontrolledFormatString.swift:30:5:30:35 | [summary param] 0 in NSString.init(string:) | | UncontrolledFormatString.swift:84:54:84:54 | tainted | UncontrolledFormatString.swift:84:37:84:61 | call to NSString.init(string:) | -| UncontrolledFormatString.swift:85:72:85:72 | tainted | UncontrolledFormatString.swift:30:5:30:35 | [summary param] 0 in NSString.init(string:) | | UncontrolledFormatString.swift:85:72:85:72 | tainted | UncontrolledFormatString.swift:85:55:85:79 | call to NSString.init(string:) | nodes -| UncontrolledFormatString.swift:30:5:30:35 | [summary param] 0 in NSString.init(string:) | semmle.label | [summary param] 0 in NSString.init(string:) | -| UncontrolledFormatString.swift:30:5:30:35 | [summary] to write: return (return) in NSString.init(string:) | semmle.label | [summary] to write: return (return) in NSString.init(string:) | | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | | UncontrolledFormatString.swift:70:28:70:28 | tainted | semmle.label | tainted | | UncontrolledFormatString.swift:73:28:73:28 | tainted | semmle.label | tainted | @@ -43,10 +36,6 @@ nodes | UncontrolledFormatString.swift:88:11:88:11 | tainted | semmle.label | tainted | | UncontrolledFormatString.swift:91:61:91:61 | tainted | semmle.label | tainted | subpaths -| UncontrolledFormatString.swift:81:47:81:47 | tainted | UncontrolledFormatString.swift:30:5:30:35 | [summary param] 0 in NSString.init(string:) | UncontrolledFormatString.swift:30:5:30:35 | [summary] to write: return (return) in NSString.init(string:) | UncontrolledFormatString.swift:81:30:81:54 | call to NSString.init(string:) | -| UncontrolledFormatString.swift:82:65:82:65 | tainted | UncontrolledFormatString.swift:30:5:30:35 | [summary param] 0 in NSString.init(string:) | UncontrolledFormatString.swift:30:5:30:35 | [summary] to write: return (return) in NSString.init(string:) | UncontrolledFormatString.swift:82:48:82:72 | call to NSString.init(string:) | -| UncontrolledFormatString.swift:84:54:84:54 | tainted | UncontrolledFormatString.swift:30:5:30:35 | [summary param] 0 in NSString.init(string:) | UncontrolledFormatString.swift:30:5:30:35 | [summary] to write: return (return) in NSString.init(string:) | UncontrolledFormatString.swift:84:37:84:61 | call to NSString.init(string:) | -| UncontrolledFormatString.swift:85:72:85:72 | tainted | UncontrolledFormatString.swift:30:5:30:35 | [summary param] 0 in NSString.init(string:) | UncontrolledFormatString.swift:30:5:30:35 | [summary] to write: return (return) in NSString.init(string:) | UncontrolledFormatString.swift:85:55:85:79 | call to NSString.init(string:) | #select | UncontrolledFormatString.swift:70:28:70:28 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | UncontrolledFormatString.swift:70:28:70:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value | | UncontrolledFormatString.swift:73:28:73:28 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | UncontrolledFormatString.swift:73:28:73:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value | diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected index 36c206ed9fd..78ddf30855b 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected @@ -2,9 +2,7 @@ edges | testAlamofire.swift:150:45:150:45 | password | testAlamofire.swift:150:13:150:45 | ... .+(_:_:) ... | | testAlamofire.swift:152:51:152:51 | password | testAlamofire.swift:152:19:152:51 | ... .+(_:_:) ... | | testAlamofire.swift:154:38:154:38 | email | testAlamofire.swift:154:14:154:46 | ... .+(_:_:) ... | -| testSend.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | testSend.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | | testSend.swift:33:14:33:32 | call to Data.init(_:) | testSend.swift:37:19:37:19 | data2 | -| testSend.swift:33:19:33:19 | passwordPlain | testSend.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | | testSend.swift:33:19:33:19 | passwordPlain | testSend.swift:33:14:33:32 | call to Data.init(_:) | | testSend.swift:41:10:41:18 | data | testSend.swift:41:45:41:45 | data | | testSend.swift:52:13:52:13 | password | testSend.swift:59:27:59:27 | str1 | @@ -22,8 +20,6 @@ nodes | testAlamofire.swift:152:51:152:51 | password | semmle.label | password | | testAlamofire.swift:154:14:154:46 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | testAlamofire.swift:154:38:154:38 | email | semmle.label | email | -| testSend.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | semmle.label | [summary param] 0 in Data.init(_:) | -| testSend.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | semmle.label | [summary] to write: return (return) in Data.init(_:) | | testSend.swift:29:19:29:19 | passwordPlain | semmle.label | passwordPlain | | testSend.swift:33:14:33:32 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | | testSend.swift:33:19:33:19 | passwordPlain | semmle.label | passwordPlain | @@ -47,7 +43,6 @@ nodes | testURL.swift:16:55:16:55 | credit_card_no | semmle.label | credit_card_no | | testURL.swift:20:22:20:22 | passwd | semmle.label | passwd | subpaths -| testSend.swift:33:19:33:19 | passwordPlain | testSend.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | testSend.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | testSend.swift:33:14:33:32 | call to Data.init(_:) | | testSend.swift:54:17:54:17 | password | testSend.swift:41:10:41:18 | data | testSend.swift:41:45:41:45 | data | testSend.swift:54:13:54:25 | call to pad(_:) | #select | testAlamofire.swift:150:13:150:45 | ... .+(_:_:) ... | testAlamofire.swift:150:45:150:45 | password | testAlamofire.swift:150:13:150:45 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testAlamofire.swift:150:45:150:45 | password | password | diff --git a/swift/ql/test/query-tests/Security/CWE-321/HardcodedEncryptionKey.expected b/swift/ql/test/query-tests/Security/CWE-321/HardcodedEncryptionKey.expected index 380823043c0..f61deac228d 100644 --- a/swift/ql/test/query-tests/Security/CWE-321/HardcodedEncryptionKey.expected +++ b/swift/ql/test/query-tests/Security/CWE-321/HardcodedEncryptionKey.expected @@ -22,12 +22,10 @@ edges | file://:0:0:0:0 | [post] self [encryptionKey] | file://:0:0:0:0 | [post] self | | file://:0:0:0:0 | [post] self [encryptionKey] | file://:0:0:0:0 | [post] self | | file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [encryptionKey] | -| misc.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | misc.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | | misc.swift:30:7:30:7 | value | file://:0:0:0:0 | value | | misc.swift:46:19:46:38 | call to Data.init(_:) | misc.swift:49:41:49:41 | myConstKey | | misc.swift:46:19:46:38 | call to Data.init(_:) | misc.swift:53:25:53:25 | myConstKey | | misc.swift:46:19:46:38 | call to Data.init(_:) | misc.swift:57:41:57:41 | myConstKey | -| misc.swift:46:24:46:24 | abcdef123456 | misc.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | | misc.swift:46:24:46:24 | abcdef123456 | misc.swift:46:19:46:38 | call to Data.init(_:) | | misc.swift:53:2:53:2 | [post] config [encryptionKey] | misc.swift:53:2:53:2 | [post] config | | misc.swift:53:25:53:25 | myConstKey | misc.swift:30:7:30:7 | value | @@ -37,7 +35,6 @@ edges | misc.swift:57:41:57:41 | myConstKey | misc.swift:30:7:30:7 | value | | misc.swift:57:41:57:41 | myConstKey | misc.swift:57:2:57:18 | [post] getter for .config | | misc.swift:57:41:57:41 | myConstKey | misc.swift:57:2:57:18 | [post] getter for .config [encryptionKey] | -| rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | | rncryptor.swift:60:19:60:38 | call to Data.init(_:) | rncryptor.swift:65:73:65:73 | myConstKey | | rncryptor.swift:60:19:60:38 | call to Data.init(_:) | rncryptor.swift:66:73:66:73 | myConstKey | | rncryptor.swift:60:19:60:38 | call to Data.init(_:) | rncryptor.swift:67:73:67:73 | myConstKey | @@ -53,7 +50,6 @@ edges | rncryptor.swift:60:19:60:38 | call to Data.init(_:) | rncryptor.swift:80:94:80:94 | myConstKey | | rncryptor.swift:60:19:60:38 | call to Data.init(_:) | rncryptor.swift:81:102:81:102 | myConstKey | | rncryptor.swift:60:19:60:38 | call to Data.init(_:) | rncryptor.swift:83:92:83:92 | myConstKey | -| rncryptor.swift:60:24:60:24 | abcdef123456 | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | | rncryptor.swift:60:24:60:24 | abcdef123456 | rncryptor.swift:60:19:60:38 | call to Data.init(_:) | nodes | cryptoswift.swift:76:3:76:3 | this string is constant | semmle.label | this string is constant | @@ -82,8 +78,6 @@ nodes | file://:0:0:0:0 | [post] self | semmle.label | [post] self | | file://:0:0:0:0 | [post] self [encryptionKey] | semmle.label | [post] self [encryptionKey] | | file://:0:0:0:0 | value | semmle.label | value | -| misc.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | semmle.label | [summary param] 0 in Data.init(_:) | -| misc.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | semmle.label | [summary] to write: return (return) in Data.init(_:) | | misc.swift:30:7:30:7 | value | semmle.label | value | | misc.swift:46:19:46:38 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | | misc.swift:46:24:46:24 | abcdef123456 | semmle.label | abcdef123456 | @@ -94,8 +88,6 @@ nodes | misc.swift:57:2:57:18 | [post] getter for .config | semmle.label | [post] getter for .config | | misc.swift:57:2:57:18 | [post] getter for .config [encryptionKey] | semmle.label | [post] getter for .config [encryptionKey] | | misc.swift:57:41:57:41 | myConstKey | semmle.label | myConstKey | -| rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | semmle.label | [summary param] 0 in Data.init(_:) | -| rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | semmle.label | [summary] to write: return (return) in Data.init(_:) | | rncryptor.swift:60:19:60:38 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | | rncryptor.swift:60:24:60:24 | abcdef123456 | semmle.label | abcdef123456 | | rncryptor.swift:65:73:65:73 | myConstKey | semmle.label | myConstKey | @@ -114,12 +106,10 @@ nodes | rncryptor.swift:81:102:81:102 | myConstKey | semmle.label | myConstKey | | rncryptor.swift:83:92:83:92 | myConstKey | semmle.label | myConstKey | subpaths -| misc.swift:46:24:46:24 | abcdef123456 | misc.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | misc.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | misc.swift:46:19:46:38 | call to Data.init(_:) | | misc.swift:53:25:53:25 | myConstKey | misc.swift:30:7:30:7 | value | file://:0:0:0:0 | [post] self | misc.swift:53:2:53:2 | [post] config | | misc.swift:53:25:53:25 | myConstKey | misc.swift:30:7:30:7 | value | file://:0:0:0:0 | [post] self [encryptionKey] | misc.swift:53:2:53:2 | [post] config [encryptionKey] | | misc.swift:57:41:57:41 | myConstKey | misc.swift:30:7:30:7 | value | file://:0:0:0:0 | [post] self | misc.swift:57:2:57:18 | [post] getter for .config | | misc.swift:57:41:57:41 | myConstKey | misc.swift:30:7:30:7 | value | file://:0:0:0:0 | [post] self [encryptionKey] | misc.swift:57:2:57:18 | [post] getter for .config [encryptionKey] | -| rncryptor.swift:60:24:60:24 | abcdef123456 | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | rncryptor.swift:60:19:60:38 | call to Data.init(_:) | #select | cryptoswift.swift:108:21:108:21 | keyString | cryptoswift.swift:76:3:76:3 | this string is constant | cryptoswift.swift:108:21:108:21 | keyString | The key 'keyString' has been initialized with hard-coded values from $@. | cryptoswift.swift:76:3:76:3 | this string is constant | this string is constant | | cryptoswift.swift:109:21:109:21 | keyString | cryptoswift.swift:76:3:76:3 | this string is constant | cryptoswift.swift:109:21:109:21 | keyString | The key 'keyString' has been initialized with hard-coded values from $@. | cryptoswift.swift:76:3:76:3 | this string is constant | this string is constant | diff --git a/swift/ql/test/query-tests/Security/CWE-760/ConstantSalt.expected b/swift/ql/test/query-tests/Security/CWE-760/ConstantSalt.expected index 6dd93198451..cd9fda87e19 100644 --- a/swift/ql/test/query-tests/Security/CWE-760/ConstantSalt.expected +++ b/swift/ql/test/query-tests/Security/CWE-760/ConstantSalt.expected @@ -1,26 +1,21 @@ edges -| rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | | rncryptor.swift:59:24:59:43 | call to Data.init(_:) | rncryptor.swift:63:57:63:57 | myConstantSalt1 | | rncryptor.swift:59:24:59:43 | call to Data.init(_:) | rncryptor.swift:68:106:68:106 | myConstantSalt1 | | rncryptor.swift:59:24:59:43 | call to Data.init(_:) | rncryptor.swift:71:106:71:106 | myConstantSalt1 | | rncryptor.swift:59:24:59:43 | call to Data.init(_:) | rncryptor.swift:75:127:75:127 | myConstantSalt1 | | rncryptor.swift:59:24:59:43 | call to Data.init(_:) | rncryptor.swift:78:135:78:135 | myConstantSalt1 | -| rncryptor.swift:59:29:59:29 | abcdef123456 | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | | rncryptor.swift:59:29:59:29 | abcdef123456 | rncryptor.swift:59:24:59:43 | call to Data.init(_:) | | rncryptor.swift:60:24:60:30 | call to Data.init(_:) | rncryptor.swift:65:55:65:55 | myConstantSalt2 | | rncryptor.swift:60:24:60:30 | call to Data.init(_:) | rncryptor.swift:69:131:69:131 | myConstantSalt2 | | rncryptor.swift:60:24:60:30 | call to Data.init(_:) | rncryptor.swift:72:131:72:131 | myConstantSalt2 | | rncryptor.swift:60:24:60:30 | call to Data.init(_:) | rncryptor.swift:76:152:76:152 | myConstantSalt2 | | rncryptor.swift:60:24:60:30 | call to Data.init(_:) | rncryptor.swift:79:160:79:160 | myConstantSalt2 | -| rncryptor.swift:60:29:60:29 | 0 | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | | rncryptor.swift:60:29:60:29 | 0 | rncryptor.swift:60:24:60:30 | call to Data.init(_:) | | test.swift:43:35:43:130 | [...] | test.swift:51:49:51:49 | constantSalt | | test.swift:43:35:43:130 | [...] | test.swift:56:59:56:59 | constantSalt | | test.swift:43:35:43:130 | [...] | test.swift:62:59:62:59 | constantSalt | | test.swift:43:35:43:130 | [...] | test.swift:67:53:67:53 | constantSalt | nodes -| rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | semmle.label | [summary param] 0 in Data.init(_:) | -| rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | semmle.label | [summary] to write: return (return) in Data.init(_:) | | rncryptor.swift:59:24:59:43 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | | rncryptor.swift:59:29:59:29 | abcdef123456 | semmle.label | abcdef123456 | | rncryptor.swift:60:24:60:30 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | @@ -41,8 +36,6 @@ nodes | test.swift:62:59:62:59 | constantSalt | semmle.label | constantSalt | | test.swift:67:53:67:53 | constantSalt | semmle.label | constantSalt | subpaths -| rncryptor.swift:59:29:59:29 | abcdef123456 | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | rncryptor.swift:59:24:59:43 | call to Data.init(_:) | -| rncryptor.swift:60:29:60:29 | 0 | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) | rncryptor.swift:5:5:5:29 | [summary] to write: return (return) in Data.init(_:) | rncryptor.swift:60:24:60:30 | call to Data.init(_:) | #select | rncryptor.swift:63:57:63:57 | myConstantSalt1 | rncryptor.swift:59:29:59:29 | abcdef123456 | rncryptor.swift:63:57:63:57 | myConstantSalt1 | The value 'abcdef123456' is used as a constant salt, which is insecure for hashing passwords. | | rncryptor.swift:65:55:65:55 | myConstantSalt2 | rncryptor.swift:60:29:60:29 | 0 | rncryptor.swift:65:55:65:55 | myConstantSalt2 | The value '0' is used as a constant salt, which is insecure for hashing passwords. | From 6942925899e0ad7ede5ebde36a0b25d7226c0338 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 22 Jun 2023 10:53:10 +0200 Subject: [PATCH 265/364] QL: Fix bad join ``` [2023-06-22 10:44:20] (92s) Tuple counts for Predicate#23818b54::Cached::resolveSelfClassCalls#2#ff/2@06fd3bf5 after 1m9s: 30500 ~567% {3} r1 = JOIN Ast#8e1d5bcf::ClassPredicate::getName#0#dispred#ff WITH Ast#8e1d5bcf::PredicateOrBuiltin::getArity#0#dispred#ff ON FIRST 1 OUTPUT Lhs.0 'p', Lhs.1, Rhs.1 26500 ~573% {4} r2 = JOIN r1 WITH Ast#8e1d5bcf::Class::getAClassPredicate#0#dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.2, Lhs.0 'p', Lhs.1, Rhs.1 3059915597 ~605% {4} r3 = JOIN r2 WITH Ast#8e1d5bcf::Call::getNumberOfArguments#0#dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'mc', Lhs.2, Lhs.1 'p', Lhs.3 20999389 ~701% {3} r4 = JOIN r3 WITH Ast#8e1d5bcf::MemberCall::getMemberName#0#dispred#ff ON FIRST 2 OUTPUT Lhs.0 'mc', Lhs.2 'p', Lhs.3 20995877 ~711% {4} r5 = JOIN r4 WITH Ast#8e1d5bcf::MemberCall::getBase#0#dispred#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'p', Lhs.2, Lhs.0 'mc' 1240332 ~700% {3} r6 = JOIN r5 WITH Ast#8e1d5bcf::ThisAccess#ff ON FIRST 1 OUTPUT Lhs.3 'mc', Lhs.1 'p', Lhs.2 1236711 ~716% {4} r7 = JOIN r6 WITH Ast#8e1d5bcf::AstNode::getEnclosingPredicate#0#dispred#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.2, Lhs.1 'p', Lhs.0 'mc' 4476 ~347% {2} r8 = JOIN r7 WITH Ast#8e1d5bcf::AstNode::getParent#0#dispred#ff ON FIRST 2 OUTPUT Lhs.3 'mc', Lhs.2 'p' return r8 ``` --- .../src/codeql_ql/ast/internal/Predicate.qll | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/ql/ql/src/codeql_ql/ast/internal/Predicate.qll b/ql/ql/src/codeql_ql/ast/internal/Predicate.qll index 46dc86113da..b45eb2166f1 100644 --- a/ql/ql/src/codeql_ql/ast/internal/Predicate.qll +++ b/ql/ql/src/codeql_ql/ast/internal/Predicate.qll @@ -90,16 +90,28 @@ private module Cached { ) } + pragma[nomagic] + private ClassPredicate getClassPredicate(Class c, string name, int arity) { + result = c.getClassPredicate(name) and + arity = result.getArity() + } + + pragma[nomagic] + private predicate resolveSelfClassCalls0(Class c, string name, int arity, MemberCall mc) { + mc.getBase() instanceof ThisAccess and + c = mc.getEnclosingPredicate().getParent() and + name = mc.getMemberName() and + arity = mc.getNumberOfArguments() + } + /** * Holds if `mc` is a `this.method()` call to a predicate defined in the same class. * helps avoid spuriously resolving to predicates in super-classes. */ private predicate resolveSelfClassCalls(MemberCall mc, PredicateOrBuiltin p) { - exists(Class c | - mc.getBase() instanceof ThisAccess and - c = mc.getEnclosingPredicate().getParent() and - p = c.getClassPredicate(mc.getMemberName()) and - p.getArity() = mc.getNumberOfArguments() + exists(Class c, string name, int arity | + resolveSelfClassCalls0(c, name, arity, mc) and + p = getClassPredicate(c, name, arity) ) } From d48f7f59c1c62eee5798cbc29c0387de69a343d7 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 22 Jun 2023 09:54:00 +0100 Subject: [PATCH 266/364] Swift: Add change note. --- swift/ql/src/change-notes/2023-06-22-hide-summarized-nodes.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 swift/ql/src/change-notes/2023-06-22-hide-summarized-nodes.md diff --git a/swift/ql/src/change-notes/2023-06-22-hide-summarized-nodes.md b/swift/ql/src/change-notes/2023-06-22-hide-summarized-nodes.md new file mode 100644 index 00000000000..3c192330ee4 --- /dev/null +++ b/swift/ql/src/change-notes/2023-06-22-hide-summarized-nodes.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* Functions and methods modeled as flow summaries are no longer shown in the path of `path-problem` queries. This results in more succinct paths for most security queries. From 04f388f8c4b64a7a79ce1a66a2dd7ad48e5f0600 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 22 Jun 2023 11:07:09 +0200 Subject: [PATCH 267/364] QL: Add more dead-code tests --- .../queries/style/DeadCode/DeadCode.expected | 10 ++++-- ql/ql/test/queries/style/DeadCode/Foo.qll | 36 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/ql/ql/test/queries/style/DeadCode/DeadCode.expected b/ql/ql/test/queries/style/DeadCode/DeadCode.expected index 5238a57c6ed..bc9ccec7012 100644 --- a/ql/ql/test/queries/style/DeadCode/DeadCode.expected +++ b/ql/ql/test/queries/style/DeadCode/DeadCode.expected @@ -1,2 +1,8 @@ -| Foo.qll:2:21:2:25 | ClasslessPredicate dead1 | This code is never used, and it's not publicly exported. | -| Foo.qll:6:13:6:17 | ClasslessPredicate dead2 | This code is never used, and it's not publicly exported. | +| Foo.qll:4:21:4:25 | ClasslessPredicate dead1 | This code is never used, and it's not publicly exported. | +| Foo.qll:8:13:8:17 | ClasslessPredicate dead2 | This code is never used, and it's not publicly exported. | +| Foo.qll:42:16:42:21 | Module Input1 | This code is never used, and it's not publicly exported. | +| Foo.qll:46:16:46:21 | Module Input2 | This code is never used, and it's not publicly exported. | +| Foo.qll:50:16:50:21 | Module Input3 | This code is never used, and it's not publicly exported. | +| Foo.qll:56:16:56:17 | Module M2 | This code is never used, and it's not publicly exported. | +| Foo.qll:64:15:64:20 | Class CImpl1 | This code is never used, and it's not publicly exported. | +| Foo.qll:68:15:68:20 | Class CImpl2 | This code is never used, and it's not publicly exported. | diff --git a/ql/ql/test/queries/style/DeadCode/Foo.qll b/ql/ql/test/queries/style/DeadCode/Foo.qll index f273e3882e3..5b13fd99ca9 100644 --- a/ql/ql/test/queries/style/DeadCode/Foo.qll +++ b/ql/ql/test/queries/style/DeadCode/Foo.qll @@ -1,3 +1,5 @@ +import ql + private module Mixed { private predicate dead1() { none() } @@ -30,3 +32,37 @@ private module Foo { module ValidationMethod { predicate impl() { sig() } } + +signature module InputSig { + predicate foo(); +} + +module ParameterizedModule { } + +private module Input1 implements InputSig { + predicate foo() { any() } +} + +private module Input2 implements InputSig { + predicate foo() { any() } +} + +private module Input3 implements InputSig { + predicate foo() { any() } +} + +module M1 = ParameterizedModule; + +private module M2 = ParameterizedModule; + +import ParameterizedModule + +private module MImpl { } + +module MPublic = MImpl; + +private class CImpl1 extends AstNode { } + +final class CPublic1 = CImpl1; + +private class CImpl2 extends AstNode { } From 0f8ebd151986ae66d4e113d8b8757a749fd2dc2f Mon Sep 17 00:00:00 2001 From: yoff Date: Thu, 22 Jun 2023 11:31:21 +0200 Subject: [PATCH 268/364] Update python/ql/test/experimental/dataflow/model-summaries/model_summaries.py Co-authored-by: Rasmus Wriedt Larsen --- .../dataflow/model-summaries/model_summaries.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py index 3a98e04ceb7..1a74df11366 100644 --- a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py +++ b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py @@ -120,7 +120,14 @@ ensure_tainted( tainted_list_implicit[0] # $ tainted ) +# Modeled flow-summary is not value preserving from json import MS_loads as json_loads + +# so no data-flow +SINK_F(json_loads(SOURCE)) +SINK_F(json_loads(SOURCE)[0]) + +# but has taint-flow tainted_resultlist = json_loads(TAINTED_STRING) ensure_tainted( tainted_resultlist, # $ tainted From 2264b119a67ffb150f48730816780d3e0259425e Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 22 Jun 2023 11:52:25 +0200 Subject: [PATCH 269/364] python: more consistent tests - do not test taint flow whne dataflow is established - test taint of both the collection and the expected element --- .../model-summaries/model_summaries.py | 41 +++++++------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py index 1a74df11366..5074814f341 100644 --- a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py +++ b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py @@ -36,18 +36,10 @@ from foo import MS_identity, MS_apply_lambda, MS_reversed, MS_list_map, MS_appen via_identity = MS_identity(SOURCE) SINK(via_identity) # $ flow="SOURCE, l:-1 -> via_identity" -tainted = MS_identity(TAINTED_STRING) -ensure_tainted(tainted) # $ tainted - - # Lambda summary via_lambda = MS_apply_lambda(lambda x: [x], SOURCE) SINK(via_lambda[0]) # $ flow="SOURCE, l:-1 -> via_lambda[0]" -tainted_lambda = MS_apply_lambda(lambda x: [x], TAINTED_STRING) -ensure_tainted(tainted_lambda) # $ tainted - - # A lambda that breaks the flow not_via_lambda = MS_apply_lambda(lambda x: 1, SOURCE) SINK_F(not_via_lambda) @@ -59,8 +51,11 @@ ensure_not_tainted(untainted_lambda) via_reversed = MS_reversed([SOURCE]) SINK(via_reversed[0]) # $ flow="SOURCE, l:-1 -> via_reversed[0]" -tainted_list = MS_reversed([TAINTED_STRING]) -ensure_tainted(tainted_list[0]) # $ tainted +tainted_list = MS_reversed(TAINTED_LIST) +ensure_tainted( + tainted_list, # $ tainted + tainted_list[0] # $ tainted + ) # Complex summaries def box(x): @@ -69,8 +64,11 @@ def box(x): via_map = MS_list_map(box, [SOURCE]) SINK(via_map[0][0]) # $ flow="SOURCE, l:-1 -> via_map[0][0]" -tainted_mapped = MS_list_map(box, [TAINTED_STRING]) -ensure_tainted(tainted_mapped[0][0]) # $ tainted +tainted_mapped = MS_list_map(box, TAINTED_LIST) +ensure_tainted( + tainted_mapped, # $ tainted + tainted_mapped[0][0] # $ tainted + ) def explicit_identity(x): return x @@ -78,25 +76,19 @@ def explicit_identity(x): via_map_explicit = MS_list_map(explicit_identity, [SOURCE]) SINK(via_map_explicit[0]) # $ flow="SOURCE, l:-1 -> via_map_explicit[0]" -tainted_mapped_explicit = MS_list_map(explicit_identity, [TAINTED_STRING]) -tainted_mapped_explicit_implicit = MS_list_map(explicit_identity, TAINTED_LIST) +tainted_mapped_explicit = MS_list_map(explicit_identity, TAINTED_LIST) ensure_tainted( tainted_mapped_explicit, # $ tainted - tainted_mapped_explicit[0], # $ tainted - tainted_mapped_explicit_implicit, # $ tainted - tainted_mapped_explicit_implicit[0] # $ tainted + tainted_mapped_explicit[0] # $ tainted ) via_map_summary = MS_list_map(MS_identity, [SOURCE]) SINK(via_map_summary[0]) # $ flow="SOURCE, l:-1 -> via_map_summary[0]" -tainted_mapped_summary = MS_list_map(MS_identity, [TAINTED_STRING]) -tainted_mapped_summary_implicit = MS_list_map(MS_identity, TAINTED_LIST) +tainted_mapped_summary = MS_list_map(MS_identity, TAINTED_LIST) ensure_tainted( tainted_mapped_summary, # $ tainted - tainted_mapped_summary[0], # $ tainted - tainted_mapped_summary_implicit, # $ tainted - tainted_mapped_summary_implicit[0] # $ tainted + tainted_mapped_summary[0] # $ tainted ) via_append_el = MS_append_to_list([], SOURCE) @@ -111,13 +103,10 @@ ensure_tainted( via_append = MS_append_to_list([SOURCE], NONSOURCE) SINK(via_append[0]) # $ flow="SOURCE, l:-1 -> via_append[0]" -tainted_list = MS_append_to_list([TAINTED_STRING], NONSOURCE) tainted_list_implicit = MS_append_to_list(TAINTED_LIST, NONSOURCE) ensure_tainted( tainted_list, # $ tainted - tainted_list[0], # $ tainted - tainted_list_implicit, # $ tainted - tainted_list_implicit[0] # $ tainted + tainted_list[0] # $ tainted ) # Modeled flow-summary is not value preserving From 5816f177c94b024d848a2152053f5472f232dc4a Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 9 Jun 2023 15:33:49 +0100 Subject: [PATCH 270/364] C++: Add failing test. --- .../dataflow-consistency.expected | 1 + .../dataflow/dataflow-tests/test.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index acf233ed2ee..55b9a1fe154 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -128,6 +128,7 @@ postWithInFlow | test.cpp:690:3:690:3 | s [post update] | PostUpdateNode should not be the target of local flow. | | test.cpp:694:4:694:6 | buf [inner post update] | PostUpdateNode should not be the target of local flow. | | test.cpp:704:23:704:25 | buf [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:715:25:715:25 | c [inner post update] | PostUpdateNode should not be the target of local flow. | viableImplInCallContextTooLarge uniqueParameterNodeAtPosition uniqueParameterNodePosition diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp index 915a8421475..ad3257fed9f 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp @@ -702,4 +702,21 @@ void call_increment_buf(int** buf) { // $ ast-def=buf void test_conflation_regression(int* source) { // $ ast-def=source int* buf = source; call_increment_buf(&buf); +} + +void write_to_star_star_p(unsigned char **p) // $ ast-def=p ir-def=**p ir-def=*p +{ + **p = 0; +} + +void write_to_star_buf(unsigned char *buf) // $ ast-def=buf +{ + unsigned char *c = buf; + write_to_star_star_p(&c); +} + +void test(unsigned char *source) // $ ast-def=source +{ + write_to_star_buf(source); + sink(*source); // $ SPURIOUS: ir } \ No newline at end of file From 9e9c811eb3c126fae7860700ef95cd46673617b2 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 9 Jun 2023 15:20:09 +0100 Subject: [PATCH 271/364] C++: Fix conflation bug in 'getIRRepresentationOfIndirectInstruction'. --- .../semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll index d8571b8b74a..55135e180d8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll @@ -796,7 +796,7 @@ private module Cached { address.getDef() = instr and isDereference(load, address) and isUseImpl(address, _, indirectionIndex - 1) and - result = instr + result = load ) } From 6034eb07afa037836dfe628ddfb7b1a4695159ab Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 9 Jun 2023 15:16:09 +0100 Subject: [PATCH 272/364] C++: Change the API for indirect operands and indirection instructions to not allow pointer conflation. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 133 +++++++++--------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index ef006bbff0a..2e6daad1f84 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -193,86 +193,89 @@ private class SingleUseOperandNode0 extends OperandNode0, TSingleUseOperandNode0 SingleUseOperandNode0() { this = TSingleUseOperandNode0(op) } } -/** - * INTERNAL: Do not use. - * - * A node that represents the indirect value of an operand in the IR - * after `index` number of loads. - * - * Note: Unlike `RawIndirectOperand`, a value of type `IndirectOperand` may - * be an `OperandNode`. - */ -class IndirectOperand extends Node { - Operand operand; - int indirectionIndex; - - IndirectOperand() { - this.(RawIndirectOperand).getOperand() = operand and - this.(RawIndirectOperand).getIndirectionIndex() = indirectionIndex - or - nodeHasOperand(this, Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex), - indirectionIndex - 1) +private module IndirectOperands { + /** + * INTERNAL: Do not use. + * + * A node that represents the indirect value of an operand in the IR + * after `index` number of loads. + * + * Note: Unlike `RawIndirectOperand`, a value of type `IndirectOperand` may + * be an `OperandNode`. + */ + abstract class IndirectOperand extends Node { + /** Gets the underlying operand. */ + abstract predicate hasOperandAndIndirectionIndex(Operand operand, int indirectionIndex); } - /** Gets the underlying operand. */ - Operand getOperand() { result = operand } + private class IndirectOperandFromRaw extends IndirectOperand instanceof RawIndirectOperand { + override predicate hasOperandAndIndirectionIndex(Operand operand, int indirectionIndex) { + operand = RawIndirectOperand.super.getOperand() and + indirectionIndex = RawIndirectOperand.super.getIndirectionIndex() + } + } - /** Gets the underlying indirection index. */ - int getIndirectionIndex() { result = indirectionIndex } + private class IndirectOperandFromIRRepr extends IndirectOperand { + Operand operand; + int indirectionIndex; - /** - * Holds if this `IndirectOperand` is represented directly in the IR instead of - * a `RawIndirectionOperand` with operand `op` and indirection index `index`. - */ - predicate isIRRepresentationOf(Operand op, int index) { - this instanceof OperandNode and - ( - op = operand and - index = indirectionIndex - ) + IndirectOperandFromIRRepr() { + exists(Operand repr | + repr = Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex) and + nodeHasOperand(this, repr, indirectionIndex - 1) + ) + } + + override predicate hasOperandAndIndirectionIndex(Operand op, int index) { + op = operand and index = indirectionIndex + } } } -/** - * INTERNAL: Do not use. - * - * A node that represents the indirect value of an instruction in the IR - * after `index` number of loads. - * - * Note: Unlike `RawIndirectInstruction`, a value of type `IndirectInstruction` may - * be an `InstructionNode`. - */ -class IndirectInstruction extends Node { - Instruction instr; - int indirectionIndex; +import IndirectOperands - IndirectInstruction() { - this.(RawIndirectInstruction).getInstruction() = instr and - this.(RawIndirectInstruction).getIndirectionIndex() = indirectionIndex - or - nodeHasInstruction(this, Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex), - indirectionIndex - 1) +private module IndirectInstructions { + /** + * INTERNAL: Do not use. + * + * A node that represents the indirect value of an instruction in the IR + * after `index` number of loads. + * + * Note: Unlike `RawIndirectInstruction`, a value of type `IndirectInstruction` may + * be an `InstructionNode`. + */ + abstract class IndirectInstruction extends Node { + /** Gets the underlying instruction. */ + abstract predicate hasInstructionAndIndirectionIndex(Instruction instr, int index); } - /** Gets the underlying instruction. */ - Instruction getInstruction() { result = instr } + private class IndirectInstructionFromRaw extends IndirectInstruction instanceof RawIndirectInstruction + { + override predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) { + instr = RawIndirectInstruction.super.getInstruction() and + index = RawIndirectInstruction.super.getIndirectionIndex() + } + } - /** Gets the underlying indirection index. */ - int getIndirectionIndex() { result = indirectionIndex } + private class IndirectInstructionFromIRRepr extends IndirectInstruction { + Instruction instr; + int indirectionIndex; - /** - * Holds if this `IndirectInstruction` is represented directly in the IR instead of - * a `RawIndirectionInstruction` with instruction `i` and indirection index `index`. - */ - predicate isIRRepresentationOf(Instruction i, int index) { - this instanceof InstructionNode and - ( - i = instr and - index = indirectionIndex - ) + IndirectInstructionFromIRRepr() { + exists(Instruction repr | + repr = Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex) and + nodeHasInstruction(this, repr, indirectionIndex - 1) + ) + } + + override predicate hasInstructionAndIndirectionIndex(Instruction i, int index) { + i = instr and index = indirectionIndex + } } } +import IndirectInstructions + /** Gets the callable in which this node occurs. */ DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() } From 3b0a286d8e6bfadf3714758d3a65b9ac76a2ab02 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 9 Jun 2023 15:19:42 +0100 Subject: [PATCH 273/364] C++: Adjust the rest of the library to the new API. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 2 +- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 48 +++++++++++-------- .../dataflow/internal/SsaInternalsCommon.qll | 2 +- .../dataflow/internal/TaintTrackingUtil.qll | 2 +- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 2e6daad1f84..49f61eb0aed 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -323,7 +323,7 @@ private class SideEffectArgumentNode extends ArgumentNode, SideEffectOperandNode override predicate argumentOf(DataFlowCall dfCall, ArgumentPosition pos) { this.getCallInstruction() = dfCall and pos.(IndirectionPosition).getArgumentIndex() = this.getArgumentIndex() and - pos.(IndirectionPosition).getIndirectionIndex() = super.getIndirectionIndex() + super.hasAddressOperandAndIndirectionIndex(_, pos.(IndirectionPosition).getIndirectionIndex()) } } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 9a3fd679f23..63e49c20c28 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -274,7 +274,7 @@ class Node extends TIRDataFlowNode { * represents the value of `**x` going into `f`. */ Expr asIndirectArgument(int index) { - this.(SideEffectOperandNode).getIndirectionIndex() = index and + this.(SideEffectOperandNode).hasAddressOperandAndIndirectionIndex(_, index) and result = this.(SideEffectOperandNode).getArgument() } @@ -317,7 +317,7 @@ class Node extends TIRDataFlowNode { index = 0 and result = this.(ExplicitParameterNode).getParameter() or - this.(IndirectParameterNode).getIndirectionIndex() = index and + this.(IndirectParameterNode).hasInstructionAndIndirectionIndex(_, index) and result = this.(IndirectParameterNode).getParameter() } @@ -577,15 +577,19 @@ class SsaPhiNode extends Node, TSsaPhiNode { * * A node representing a value after leaving a function. */ -class SideEffectOperandNode extends Node, IndirectOperand { +class SideEffectOperandNode extends Node instanceof IndirectOperand { CallInstruction call; int argumentIndex; - SideEffectOperandNode() { operand = call.getArgumentOperand(argumentIndex) } + SideEffectOperandNode() { + IndirectOperand.super.hasOperandAndIndirectionIndex(call.getArgumentOperand(argumentIndex), _) + } CallInstruction getCallInstruction() { result = call } - Operand getAddressOperand() { result = operand } + predicate hasAddressOperandAndIndirectionIndex(Operand operand, int indirectionIndex) { + IndirectOperand.super.hasOperandAndIndirectionIndex(operand, indirectionIndex) + } int getArgumentIndex() { result = argumentIndex } @@ -665,10 +669,10 @@ class InitialGlobalValue extends Node, TInitialGlobalValue { * * A node representing an indirection of a parameter. */ -class IndirectParameterNode extends Node, IndirectInstruction { +class IndirectParameterNode extends Node instanceof IndirectInstruction { InitializeParameterInstruction init; - IndirectParameterNode() { this.getInstruction() = init } + IndirectParameterNode() { IndirectInstruction.super.hasInstructionAndIndirectionIndex(init, _) } int getArgumentIndex() { init.hasIndex(result) } @@ -677,7 +681,12 @@ class IndirectParameterNode extends Node, IndirectInstruction { override Declaration getEnclosingCallable() { result = this.getFunction() } - override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() } + override Declaration getFunction() { result = init.getEnclosingFunction() } + + /** Gets the underlying instruction. */ + predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) { + IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index) + } override Location getLocationImpl() { result = this.getParameter().getLocation() } @@ -699,7 +708,8 @@ class IndirectReturnNode extends Node { IndirectReturnNode() { this instanceof FinalParameterNode or - this.(IndirectOperand).getOperand() = any(ReturnValueInstruction ret).getReturnAddressOperand() + this.(IndirectOperand) + .hasOperandAndIndirectionIndex(any(ReturnValueInstruction ret).getReturnAddressOperand(), _) } override Declaration getEnclosingCallable() { result = this.getFunction() } @@ -722,7 +732,7 @@ class IndirectReturnNode extends Node { int getIndirectionIndex() { result = this.(FinalParameterNode).getIndirectionIndex() or - result = this.(IndirectOperand).getIndirectionIndex() + this.(IndirectOperand).hasOperandAndIndirectionIndex(_, result) } } @@ -1106,7 +1116,8 @@ predicate exprNodeShouldBeInstruction(Node node, Expr e) { /** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */ predicate indirectExprNodeShouldBeIndirectInstruction(IndirectInstruction node, Expr e) { exists(Instruction instr | - instr = node.getInstruction() and not indirectExprNodeShouldBeIndirectOperand(_, e) + node.hasInstructionAndIndirectionIndex(instr, _) and + not indirectExprNodeShouldBeIndirectOperand(_, e) | e = instr.(VariableAddressInstruction).getAst().(Expr).getFullyConverted() or @@ -1307,8 +1318,8 @@ pragma[noinline] private predicate indirectParameterNodeHasArgumentIndexAndIndex( IndirectParameterNode node, int argumentIndex, int indirectionIndex ) { - node.getArgumentIndex() = argumentIndex and - node.getIndirectionIndex() = indirectionIndex + node.hasInstructionAndIndirectionIndex(_, indirectionIndex) and + node.getArgumentIndex() = argumentIndex } /** A synthetic parameter to model the pointed-to object of a pointer parameter. */ @@ -1479,18 +1490,14 @@ VariableNode variableNode(Variable v) { */ Node uninitializedNode(LocalVariable v) { none() } -pragma[noinline] predicate hasOperandAndIndex(IndirectOperand indirectOperand, Operand operand, int indirectionIndex) { - indirectOperand.getOperand() = operand and - indirectOperand.getIndirectionIndex() = indirectionIndex + indirectOperand.hasOperandAndIndirectionIndex(operand, indirectionIndex) } -pragma[noinline] predicate hasInstructionAndIndex( IndirectInstruction indirectInstr, Instruction instr, int indirectionIndex ) { - indirectInstr.getInstruction() = instr and - indirectInstr.getIndirectionIndex() = indirectionIndex + indirectInstr.hasInstructionAndIndirectionIndex(instr, indirectionIndex) } cached @@ -1656,8 +1663,7 @@ module ExprFlowCached { private predicate isIndirectBaseOfArrayAccess(IndirectOperand n, Expr e) { exists(LoadInstruction load, PointerArithmeticInstruction pai | pai = load.getSourceAddress() and - pai.getLeftOperand() = n.getOperand() and - n.getIndirectionIndex() = 1 and + n.hasOperandAndIndirectionIndex(pai.getLeftOperand(), 1) and e = load.getConvertedResultExpression() ) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll index 55135e180d8..b0e092eda62 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll @@ -263,7 +263,7 @@ private module IteratorIndirections { // Taint through `operator+=` and `operator-=` on iterators. call.getStaticCallTarget() instanceof Iterator::IteratorAssignArithmeticOperator and node2.(IndirectArgumentOutNode).getPreUpdateNode() = node1 and - node1.(IndirectOperand).getOperand() = call.getArgumentOperand(0) and + node1.(IndirectOperand).hasOperandAndIndirectionIndex(call.getArgumentOperand(0), _) and node1.getType().getUnspecifiedType() = this ) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index c3b8765a72a..028f5bad9da 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -160,7 +160,7 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) { FunctionInput modelIn, FunctionOutput modelOut | indirectArgument = callInput(call, modelIn) and - indirectArgument.getAddressOperand() = nodeIn.asOperand() and + indirectArgument.hasAddressOperandAndIndirectionIndex(nodeIn.asOperand(), _) and call.getStaticCallTarget() = func and ( func.(DataFlowFunction).hasDataFlow(modelIn, modelOut) From 6543da9990fe0a0d62c05b2bdbdb3b6c755eeb86 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 9 Jun 2023 15:35:22 +0100 Subject: [PATCH 274/364] C++: Accept test changes. --- cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp index ad3257fed9f..7a04a53510a 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp @@ -718,5 +718,5 @@ void write_to_star_buf(unsigned char *buf) // $ ast-def=buf void test(unsigned char *source) // $ ast-def=source { write_to_star_buf(source); - sink(*source); // $ SPURIOUS: ir + sink(*source); // clean } \ No newline at end of file From 3365ff0d95e49119cffb272b73e682f9482ba759 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 9 Jun 2023 15:46:04 +0100 Subject: [PATCH 275/364] C++: Ensure that 'PrintIR' for dataflow still compiles. --- .../cpp/ir/dataflow/internal/PrintIRFieldFlowSteps.qll | 4 ++-- .../code/cpp/ir/dataflow/internal/PrintIRUtilities.qll | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRFieldFlowSteps.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRFieldFlowSteps.qll index f0286c00cbc..c0976f8c3e9 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRFieldFlowSteps.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRFieldFlowSteps.qll @@ -13,7 +13,7 @@ class FieldFlowPropertyProvider extends IRPropertyProvider { override string getOperandProperty(Operand operand, string key) { exists(PostFieldUpdateNode pfun, Content content | key = "store " + content.toString() and - operand = pfun.getPreUpdateNode().(IndirectOperand).getOperand() and + pfun.getPreUpdateNode().(IndirectOperand).hasOperandAndIndirectionIndex(operand, _) and result = strictconcat(string element, Node node | storeStep(node, content, pfun) and @@ -25,7 +25,7 @@ class FieldFlowPropertyProvider extends IRPropertyProvider { or exists(Node node2, Content content | key = "read " + content.toString() and - operand = node2.(IndirectOperand).getOperand() and + node2.(IndirectOperand).hasOperandAndIndirectionIndex(operand, _) and result = strictconcat(string element, Node node1 | readStep(node1, content, node2) and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll index 5c6cdebf800..5cca78588f0 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll @@ -18,9 +18,12 @@ private string stars(int k) { } string starsForNode(Node node) { - result = stars(node.(IndirectInstruction).getIndirectionIndex()) - or - result = stars(node.(IndirectOperand).getIndirectionIndex()) + exists(int indirectionIndex | + node.(IndirectInstruction).hasInstructionAndIndirectionIndex(_, indirectionIndex) or + node.(IndirectOperand).hasOperandAndIndirectionIndex(_, indirectionIndex) + | + result = stars(indirectionIndex) + ) or not node instanceof IndirectInstruction and not node instanceof IndirectOperand and From c7cff373de79c2fb2c14b5a4d152f98a6dfc52bf Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 9 Jun 2023 15:50:52 +0100 Subject: [PATCH 276/364] C++: Add another testcase with conflation. --- .../dataflow-consistency.expected | 3 +++ .../dataflow/dataflow-tests/test.cpp | 18 ++++++++++++++++-- .../dataflow-tests/uninitialized.expected | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index 55b9a1fe154..6129ed657ac 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -129,6 +129,9 @@ postWithInFlow | test.cpp:694:4:694:6 | buf [inner post update] | PostUpdateNode should not be the target of local flow. | | test.cpp:704:23:704:25 | buf [inner post update] | PostUpdateNode should not be the target of local flow. | | test.cpp:715:25:715:25 | c [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:728:3:728:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:728:4:728:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. | +| test.cpp:734:41:734:41 | x [inner post update] | PostUpdateNode should not be the target of local flow. | viableImplInCallContextTooLarge uniqueParameterNodeAtPosition uniqueParameterNodePosition diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp index 7a04a53510a..7b6ea0fa718 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp @@ -715,8 +715,22 @@ void write_to_star_buf(unsigned char *buf) // $ ast-def=buf write_to_star_star_p(&c); } -void test(unsigned char *source) // $ ast-def=source +void test_write_to_star_buf(unsigned char *source) // $ ast-def=source { write_to_star_buf(source); sink(*source); // clean -} \ No newline at end of file +} + +void does_not_write_source_to_dereference(int *p) // $ ast-def=p ir-def=*p +{ + int x = source(); + p = &x; + *p = 42; +} + +void test_does_not_write_source_to_dereference() +{ + int x; + does_not_write_source_to_dereference(&x); + sink(x); // $ ast,ir=733:7 SPURIOUS: ast,ir=726:11 +} diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected index 0a52d928028..b40148f4950 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected @@ -42,3 +42,5 @@ | test.cpp:551:9:551:9 | y | test.cpp:552:28:552:28 | y | | test.cpp:595:8:595:9 | xs | test.cpp:596:3:596:4 | xs | | test.cpp:595:8:595:9 | xs | test.cpp:597:9:597:10 | xs | +| test.cpp:733:7:733:7 | x | test.cpp:734:41:734:41 | x | +| test.cpp:733:7:733:7 | x | test.cpp:735:8:735:8 | x | From 6528985a2726a97ba3b6144999bb7c693c18e611 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 9 Jun 2023 15:53:48 +0100 Subject: [PATCH 277/364] C++: Add QLDoc to 'hasAddressOperandAndIndirectionIndex'. --- cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 63e49c20c28..02cca5cdddb 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -587,6 +587,7 @@ class SideEffectOperandNode extends Node instanceof IndirectOperand { CallInstruction getCallInstruction() { result = call } + /** Gets the underlying operand and the underlying indirection index. */ predicate hasAddressOperandAndIndirectionIndex(Operand operand, int indirectionIndex) { IndirectOperand.super.hasOperandAndIndirectionIndex(operand, indirectionIndex) } From a8a04c8588cfbc970736db4c70a6c35e101fcf14 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 10 Jun 2023 16:12:21 +0100 Subject: [PATCH 278/364] Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com> --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 49f61eb0aed..c9331e18ca4 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -204,7 +204,7 @@ private module IndirectOperands { * be an `OperandNode`. */ abstract class IndirectOperand extends Node { - /** Gets the underlying operand. */ + /** Gets the underlying operand and the underlying indirection index. */ abstract predicate hasOperandAndIndirectionIndex(Operand operand, int indirectionIndex); } From 4f1b2c619434ef299f393a8e5aebcd1d061c9870 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 10 Jun 2023 16:12:28 +0100 Subject: [PATCH 279/364] Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com> --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index c9331e18ca4..42a496843d3 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -245,7 +245,7 @@ private module IndirectInstructions { * be an `InstructionNode`. */ abstract class IndirectInstruction extends Node { - /** Gets the underlying instruction. */ + /** Gets the underlying operand and the underlying indirection index. */ abstract predicate hasInstructionAndIndirectionIndex(Instruction instr, int index); } From ff3c76c1faa91a5f671b5644a4d858f67fc1957b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 10 Jun 2023 16:12:33 +0100 Subject: [PATCH 280/364] Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com> --- .../lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 02cca5cdddb..4cf5cd65fa8 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -684,7 +684,7 @@ class IndirectParameterNode extends Node instanceof IndirectInstruction { override Declaration getFunction() { result = init.getEnclosingFunction() } - /** Gets the underlying instruction. */ + /** Gets the underlying operand and the underlying indirection index. */ predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) { IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index) } From 273e5bc21feba3c7618a8392f79c4b95ae73fc05 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sun, 18 Jun 2023 13:12:23 +0100 Subject: [PATCH 281/364] C++: Add testcase demonstrating that the model for 'strncpy' is broken. --- .../dataflow/taint-tests/localTaint.expected | 14 ++++++++++++++ .../library-tests/dataflow/taint-tests/taint.cpp | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index f6a7625b57a..44965a9f2d9 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -6591,6 +6591,20 @@ | taint.cpp:702:4:702:6 | ... ++ | taint.cpp:703:8:703:8 | p | TAINT | | taint.cpp:702:10:702:11 | * ... | taint.cpp:702:3:702:11 | ... = ... | | | taint.cpp:702:11:702:11 | s | taint.cpp:702:10:702:11 | * ... | TAINT | +| taint.cpp:709:25:709:25 | d | taint.cpp:709:25:709:25 | d | | +| taint.cpp:709:25:709:25 | d | taint.cpp:711:10:711:10 | d | | +| taint.cpp:709:25:709:25 | d | taint.cpp:712:7:712:7 | d | | +| taint.cpp:709:34:709:34 | s | taint.cpp:709:34:709:34 | s | | +| taint.cpp:709:34:709:34 | s | taint.cpp:710:18:710:18 | s | | +| taint.cpp:709:34:709:34 | s | taint.cpp:711:13:711:13 | s | | +| taint.cpp:710:18:710:18 | ref arg s | taint.cpp:709:34:709:34 | s | | +| taint.cpp:710:18:710:18 | ref arg s | taint.cpp:711:13:711:13 | s | | +| taint.cpp:711:10:711:10 | d | taint.cpp:711:2:711:8 | call to strncpy | | +| taint.cpp:711:10:711:10 | ref arg d | taint.cpp:709:25:709:25 | d | | +| taint.cpp:711:10:711:10 | ref arg d | taint.cpp:712:7:712:7 | d | | +| taint.cpp:711:13:711:13 | s | taint.cpp:711:2:711:8 | call to strncpy | TAINT | +| taint.cpp:711:13:711:13 | s | taint.cpp:711:10:711:10 | ref arg d | TAINT | +| taint.cpp:712:7:712:7 | ref arg d | taint.cpp:709:25:709:25 | d | | | vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | | | vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | | | vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | | 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 fa6074e44f6..5c582b67cd7 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -702,4 +702,12 @@ namespace strings { *p++ = *s; sink(p); // $ ast ir } +} + +char * strncpy (char *, const char *, unsigned long); + +void test_strncpy(char* d, char* s) { + argument_source(s); + strncpy(d, s, 16); + sink(d); // $ ast MISSING: ir } \ No newline at end of file From fe97572f70175893951a20bc70fd6016b3484919 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sun, 18 Jun 2023 13:13:28 +0100 Subject: [PATCH 282/364] C++: Fix strncpy model. --- cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll | 2 +- cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll index 10b160dee47..ea371de958a 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll @@ -108,7 +108,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid // these may do only a partial copy of the input buffer to the output // buffer exists(this.getParamSize()) and - input.isParameter(this.getParamSrc()) and + input.isParameterDeref(this.getParamSrc()) and ( output.isParameterDeref(this.getParamDest()) or output.isReturnValueDeref() 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 5c582b67cd7..9810418a95e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -709,5 +709,5 @@ char * strncpy (char *, const char *, unsigned long); void test_strncpy(char* d, char* s) { argument_source(s); strncpy(d, s, 16); - sink(d); // $ ast MISSING: ir + sink(d); // $ ast ir } \ No newline at end of file From 90499c0b17ef11491eaf7f35be58b0900f2bf7e4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 22 Jun 2023 12:09:22 +0100 Subject: [PATCH 283/364] Update swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll Co-authored-by: Mathias Vorreiter Pedersen --- swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll index d1dff2c3ed7..d73c4d5bef2 100644 --- a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll +++ b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll @@ -121,7 +121,7 @@ abstract class RegExp extends Expr { ) } - /** Whether there is a character class, between start (inclusive) and end (exclusive) */ + /** Whether there is a character class, between start (inclusive) and end (exclusive). */ predicate charSet(int start, int end) { exists(int innerStart, int innerEnd | this.charSetStart(start, innerStart) and From 104dab4b660d5bf0547cc3b7a852b4eddbed9fa0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 22 Jun 2023 11:30:07 +0200 Subject: [PATCH 284/364] QL: Improve dead-code query --- ql/ql/src/codeql_ql/ast/Ast.qll | 45 ++++++++++++++++++- ql/ql/src/codeql_ql/style/DeadCodeQuery.qll | 10 +++++ .../queries/style/DeadCode/DeadCode.expected | 3 -- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/ql/ql/src/codeql_ql/ast/Ast.qll b/ql/ql/src/codeql_ql/ast/Ast.qll index 19cf38c3f1c..acc36be15ee 100644 --- a/ql/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/ql/src/codeql_ql/ast/Ast.qll @@ -567,7 +567,7 @@ class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclarati override predicate isPrivate() { Predicate.super.isPrivate() } /** Holds if this classless predicate is a signature predicate with no body. */ - predicate isSignature() { not exists(this.getBody()) } + override predicate isSignature() { not exists(this.getBody()) } override QLDoc getQLDoc() { result = any(TopLevel m).getQLDocFor(this) @@ -836,6 +836,12 @@ class Module extends TModule, ModuleDeclaration { toMock(result) = mod.asRight().getMember(i) } + pragma[nomagic] + Declaration getDeclaration(string name) { + result = this.getAMember() and + name = result.getName() + } + QLDoc getQLDocFor(AstNode m) { exists(int i | result = this.getMember(i) and m = this.getMember(i + 1)) } @@ -885,6 +891,33 @@ class ModuleMember extends TModuleMember, AstNode { predicate isFinal() { this.hasAnnotation("final") } } +private newtype TDeclarationKind = + TClassKind() or + TModuleKind() or + TPredicateKind(int arity) { arity = any(Predicate p).getArity() } + +private TDeclarationKind getDeclarationKind(Declaration d) { + d instanceof Class and result = TClassKind() + or + d instanceof Module and result = TModuleKind() + or + d = any(Predicate p | result = TPredicateKind(p.getArity())) +} + +/** Holds if module `m` must implement signature declaration `d` with name `name` and kind `kind`. */ +pragma[nomagic] +private predicate mustImplement(Module m, string name, TDeclarationKind kind, Declaration d) { + d = m.getImplements(_).getResolvedType().getDeclaration().(Module).getAMember() and + name = d.getName() and + kind = getDeclarationKind(d) +} + +pragma[nomagic] +private Declaration getDeclaration(Module m, string name, TDeclarationKind kind) { + result = m.getDeclaration(name) and + kind = getDeclarationKind(result) +} + /** A declaration. E.g. a class, type, predicate, newtype... */ class Declaration extends TDeclaration, AstNode { /** Gets the name of this declaration. */ @@ -899,6 +932,16 @@ class Declaration extends TDeclaration, AstNode { or result = any(Class c).getQLDocFor(this) } + + predicate isSignature() { this.hasAnnotation("signature") } + + /** Holds if this declaration implements `other`. */ + predicate implements(Declaration other) { + exists(Module m, string name, TDeclarationKind kind | + this = getDeclaration(m, name, kind) and + mustImplement(m, name, kind, other) + ) + } } /** An entity that can be declared in a module. */ diff --git a/ql/ql/src/codeql_ql/style/DeadCodeQuery.qll b/ql/ql/src/codeql_ql/style/DeadCodeQuery.qll index 5d6e1dc3ff7..211084f2915 100644 --- a/ql/ql/src/codeql_ql/style/DeadCodeQuery.qll +++ b/ql/ql/src/codeql_ql/style/DeadCodeQuery.qll @@ -186,6 +186,16 @@ private AstNode aliveStep(AstNode prev) { result = prev.(Module).getImplements(_) or result = prev.(PredicateExpr).getQualifier() + or + // a module argument is live if the constructed module is + result = prev.(ModuleExpr).getArgument(_) + or + // a type declaration is live if a reference to it is live + result = prev.(TypeExpr).getResolvedType().getDeclaration() + or + // a module member that implements a signature member is live if the module is + prev.(Module).getAMember() = result and + result.(Declaration).implements(_) } private AstNode deprecated() { diff --git a/ql/ql/test/queries/style/DeadCode/DeadCode.expected b/ql/ql/test/queries/style/DeadCode/DeadCode.expected index bc9ccec7012..017cf546a92 100644 --- a/ql/ql/test/queries/style/DeadCode/DeadCode.expected +++ b/ql/ql/test/queries/style/DeadCode/DeadCode.expected @@ -1,8 +1,5 @@ | Foo.qll:4:21:4:25 | ClasslessPredicate dead1 | This code is never used, and it's not publicly exported. | | Foo.qll:8:13:8:17 | ClasslessPredicate dead2 | This code is never used, and it's not publicly exported. | -| Foo.qll:42:16:42:21 | Module Input1 | This code is never used, and it's not publicly exported. | | Foo.qll:46:16:46:21 | Module Input2 | This code is never used, and it's not publicly exported. | -| Foo.qll:50:16:50:21 | Module Input3 | This code is never used, and it's not publicly exported. | | Foo.qll:56:16:56:17 | Module M2 | This code is never used, and it's not publicly exported. | -| Foo.qll:64:15:64:20 | Class CImpl1 | This code is never used, and it's not publicly exported. | | Foo.qll:68:15:68:20 | Class CImpl2 | This code is never used, and it's not publicly exported. | From 1c1637a886ddda62df8e397d7a90f3baeb088239 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:56:06 +0100 Subject: [PATCH 285/364] Ruby: Correct QLDoc for charRange. --- ruby/ql/lib/codeql/ruby/regexp/internal/ParseRegExp.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/regexp/internal/ParseRegExp.qll b/ruby/ql/lib/codeql/ruby/regexp/internal/ParseRegExp.qll index 9160bf60506..d1a39e29fd2 100644 --- a/ruby/ql/lib/codeql/ruby/regexp/internal/ParseRegExp.qll +++ b/ruby/ql/lib/codeql/ruby/regexp/internal/ParseRegExp.qll @@ -195,8 +195,8 @@ abstract class RegExp extends Ast::StringlikeLiteral { /** * Holds if the character set starting at `charset_start` contains a character range - * with lower bound found between `start` and `lower_end` - * and upper bound found between `upper_start` and `end`. + * with lower bound found between `start` and `lowerEnd` + * and upper bound found between `upperStart` and `end`. */ predicate charRange(int charsetStart, int start, int lowerEnd, int upperStart, int end) { exists(int index | From d06f4b95676f51d17748bff04a21fc2593c33147 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:56:42 +0100 Subject: [PATCH 286/364] Ruby: Correct QLDoc for qualifiedPart. --- ruby/ql/lib/codeql/ruby/regexp/internal/ParseRegExp.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/regexp/internal/ParseRegExp.qll b/ruby/ql/lib/codeql/ruby/regexp/internal/ParseRegExp.qll index d1a39e29fd2..d1f96ec407e 100644 --- a/ruby/ql/lib/codeql/ruby/regexp/internal/ParseRegExp.qll +++ b/ruby/ql/lib/codeql/ruby/regexp/internal/ParseRegExp.qll @@ -844,11 +844,11 @@ abstract class RegExp extends Ast::StringlikeLiteral { } /** - * Holds if a qualified part is found between `start` and `part_end` and the qualifier is - * found between `part_end` and `end`. + * Holds if a qualified part is found between `start` and `partEnd` and the qualifier is + * found between `partEnd` and `end`. * - * `maybe_empty` is true if the part is optional. - * `may_repeat_forever` is true if the part may be repeated unboundedly. + * `maybeEmpty` is true if the part is optional. + * `mayRepeatForever` is true if the part may be repeated unboundedly. */ predicate qualifiedPart( int start, int partEnd, int end, boolean maybeEmpty, boolean mayRepeatForever From c17de99c8660f24ef38248ed7c67c0b85bf22c35 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:59:16 +0100 Subject: [PATCH 287/364] Swift: Correct QLDoc error. --- swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll index d73c4d5bef2..fb4ff566d9f 100644 --- a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll +++ b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll @@ -855,7 +855,7 @@ abstract class RegExp extends Expr { /** * Holds if a qualified part is found between `start` and `partEnd` and the qualifier is - * found between `part_end` and `end`. + * found between `partEnd` and `end`. * * `maybeEmpty` is true if the part is optional. * `mayRepeatForever` is true if the part may be repeated unboundedly. From d07e2862f9906917e23167458e3c354dd3739ca6 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Thu, 22 Jun 2023 17:36:54 +0200 Subject: [PATCH 288/364] Java: Add URL.toString summary This adds coverage for CVE-2023-35149. --- java/ql/lib/change-notes/2023-06-22-url-tostring-model.md | 4 ++++ java/ql/lib/ext/java.net.model.yml | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 java/ql/lib/change-notes/2023-06-22-url-tostring-model.md diff --git a/java/ql/lib/change-notes/2023-06-22-url-tostring-model.md b/java/ql/lib/change-notes/2023-06-22-url-tostring-model.md new file mode 100644 index 00000000000..fc5a58ce4e6 --- /dev/null +++ b/java/ql/lib/change-notes/2023-06-22-url-tostring-model.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added a missing summary model for the method `java.net.URL.toString`. diff --git a/java/ql/lib/ext/java.net.model.yml b/java/ql/lib/ext/java.net.model.yml index 39a4c484112..24591459432 100644 --- a/java/ql/lib/ext/java.net.model.yml +++ b/java/ql/lib/ext/java.net.model.yml @@ -45,7 +45,8 @@ extensions: - ["java.net", "URI", False, "toURL", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["java.net", "URL", False, "URL", "(String)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["java.net", "URL", False, "URL", "(URL,String)", "", "Argument[0]", "Argument[this]", "taint", "ai-manual"] - - ["java.net", "URL", False, "URL", "(URL,String)", "", "Argument[1]", "Argument[this]", "taint", "ai-manual"] # @atorralba: review for consistency + - ["java.net", "URL", False, "URL", "(URL,String)", "", "Argument[1]", "Argument[this]", "taint", "ai-manual"] - ["java.net", "URL", False, "toExternalForm", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["java.net", "URL", False, "toURI", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] + - ["java.net", "URL", False, "toString", "", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["java.net", "URLDecoder", False, "decode", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] From a8aa33510d81ad39d1023b9e7200545084ac77e6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 22 Jun 2023 17:19:43 +0100 Subject: [PATCH 289/364] Shared: QLDoc NfaUtils::Make::State::hasLocationInfo. --- shared/regex/codeql/regex/nfa/NfaUtils.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shared/regex/codeql/regex/nfa/NfaUtils.qll b/shared/regex/codeql/regex/nfa/NfaUtils.qll index b690bfdd5e9..005228e8970 100644 --- a/shared/regex/codeql/regex/nfa/NfaUtils.qll +++ b/shared/regex/codeql/regex/nfa/NfaUtils.qll @@ -864,6 +864,9 @@ module Make { */ RegExpTerm getRepr() { result = repr } + /** + * Holds if the term represented by this state is found at the specified location offsets. + */ predicate hasLocationInfo(string file, int line, int column, int endline, int endcolumn) { repr.hasLocationInfo(file, line, column, endline, endcolumn) } From 0d05f50aaaf7fddda7e1f3e233691df73e9c8cc4 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Thu, 22 Jun 2023 18:12:13 +0100 Subject: [PATCH 290/364] Kotlin: Remove an expected-no-getter exception We're not sure why it was necessary. --- java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index b37d46080a6..6e5d921a406 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -1559,7 +1559,7 @@ open class KotlinFileExtractor( val setter = p.setter if (getter == null) { - if (p.modality != Modality.FINAL || !isExternalDeclaration(p)) { + if (!isExternalDeclaration(p)) { logger.warnElement("IrProperty without a getter", p) } } else if (shouldExtractDecl(getter, extractPrivateMembers)) { From da54751d8506f8e9d8acc91cc560a1e92e170e87 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 22 Jun 2023 17:37:27 +0100 Subject: [PATCH 291/364] C++: Add testcase that demonstrate the need for self-flow out of indirect parameters. --- .../dataflow-consistency.expected | 2 ++ .../dataflow-tests/self_parameter_flow.cpp | 14 ++++++++ .../test_self_parameter_flow.expected | 2 ++ .../test_self_parameter_flow.ql | 34 +++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/dataflow-tests/self_parameter_flow.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.expected create mode 100644 cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.ql diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index 6129ed657ac..eb9e8efb1d2 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -67,6 +67,8 @@ postWithInFlow | ref.cpp:109:9:109:11 | val [post update] | PostUpdateNode should not be the target of local flow. | | ref.cpp:113:11:113:13 | val [post update] | PostUpdateNode should not be the target of local flow. | | ref.cpp:115:11:115:13 | val [post update] | PostUpdateNode should not be the target of local flow. | +| self_parameter_flow.cpp:3:4:3:5 | ps [inner post update] | PostUpdateNode should not be the target of local flow. | +| self_parameter_flow.cpp:8:9:8:9 | s [inner post update] | PostUpdateNode should not be the target of local flow. | | test.cpp:91:3:91:9 | source1 [post update] | PostUpdateNode should not be the target of local flow. | | test.cpp:115:3:115:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. | | test.cpp:115:4:115:6 | out [inner post update] | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/self_parameter_flow.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/self_parameter_flow.cpp new file mode 100644 index 00000000000..1c9d3aebf99 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/self_parameter_flow.cpp @@ -0,0 +1,14 @@ +void incr(unsigned char **ps) // $ ast-def=ps ir-def=*ps ir-def=**ps +{ + *ps += 1; +} + +void callincr(unsigned char *s) // $ ast-def=s +{ + incr(&s); +} + +void test(unsigned char *s) // $ ast-def=s +{ + callincr(s); // $ MISSING: flow +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.expected new file mode 100644 index 00000000000..48de9172b36 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.ql b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.ql new file mode 100644 index 00000000000..c6ea9c5c96f --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.ql @@ -0,0 +1,34 @@ +import cpp +import semmle.code.cpp.dataflow.new.DataFlow +import TestUtilities.InlineExpectationsTest + +module TestConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source.getLocation().getFile().getBaseName() = "self_parameter_flow.cpp" and + source.asIndirectArgument() = + any(Call call | call.getTarget().hasName("callincr")).getAnArgument() + } + + predicate isSink(DataFlow::Node sink) { + sink.asDefiningArgument() = + any(Call call | call.getTarget().hasName("callincr")).getAnArgument() + } +} + +import DataFlow::Global + +module TestSelfParameterFlow implements TestSig { + string getARelevantTag() { result = "flow" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(DataFlow::Node sink | + flowTo(sink) and + location = sink.getLocation() and + element = sink.toString() and + tag = "flow" and + value = "" + ) + } +} + +import MakeTest From 0839c1aad1d2312cf066dbfe52c407036a833cd8 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 22 Jun 2023 17:38:06 +0100 Subject: [PATCH 292/364] C++: Allow self-flow through indirect parameters. --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 42a496843d3..6715b67c382 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -848,7 +848,7 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves * One example would be to allow flow like `p.foo = p.bar;`, which is disallowed * by default as a heuristic. */ -predicate allowParameterReturnInSelf(ParameterNode p) { none() } +predicate allowParameterReturnInSelf(ParameterNode p) { p instanceof IndirectParameterNode } private predicate fieldHasApproxName(Field f, string s) { s = f.getName().charAt(0) and From 79fb6a6079e60c4275d103dc5be63008e2f47de9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 22 Jun 2023 17:38:28 +0100 Subject: [PATCH 293/364] C++: Accept test changes. --- .../dataflow/dataflow-tests/self_parameter_flow.cpp | 2 +- .../CWE-119/semmle/tests/OverflowDestination.expected | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/self_parameter_flow.cpp b/cpp/ql/test/library-tests/dataflow/dataflow-tests/self_parameter_flow.cpp index 1c9d3aebf99..2298e644b05 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/self_parameter_flow.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/self_parameter_flow.cpp @@ -10,5 +10,5 @@ void callincr(unsigned char *s) // $ ast-def=s void test(unsigned char *s) // $ ast-def=s { - callincr(s); // $ MISSING: flow + callincr(s); // $ flow } \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowDestination.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowDestination.expected index 19de8c61578..8d46c8fe99b 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowDestination.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowDestination.expected @@ -8,13 +8,19 @@ edges | overflowdestination.cpp:23:45:23:48 | argv indirection | overflowdestination.cpp:30:17:30:20 | arg1 indirection | | overflowdestination.cpp:23:45:23:48 | argv indirection | overflowdestination.cpp:30:17:30:20 | arg1 indirection | | overflowdestination.cpp:43:8:43:10 | fgets output argument | overflowdestination.cpp:46:15:46:17 | src indirection | +| overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:53:9:53:12 | memcpy output argument | | overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:53:15:53:17 | src indirection | | overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:53:15:53:17 | src indirection | +| overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:54:9:54:12 | memcpy output argument | +| overflowdestination.cpp:53:9:53:12 | memcpy output argument | overflowdestination.cpp:54:9:54:12 | memcpy output argument | +| overflowdestination.cpp:54:9:54:12 | memcpy output argument | overflowdestination.cpp:54:9:54:12 | memcpy output argument | | overflowdestination.cpp:57:52:57:54 | src indirection | overflowdestination.cpp:64:16:64:19 | src2 indirection | | overflowdestination.cpp:57:52:57:54 | src indirection | overflowdestination.cpp:64:16:64:19 | src2 indirection | | overflowdestination.cpp:73:8:73:10 | fgets output argument | overflowdestination.cpp:75:30:75:32 | src indirection | | overflowdestination.cpp:73:8:73:10 | fgets output argument | overflowdestination.cpp:76:30:76:32 | src indirection | +| overflowdestination.cpp:75:30:75:32 | overflowdest_test2 output argument | overflowdestination.cpp:76:30:76:32 | src indirection | | overflowdestination.cpp:75:30:75:32 | src indirection | overflowdestination.cpp:50:52:50:54 | src indirection | +| overflowdestination.cpp:75:30:75:32 | src indirection | overflowdestination.cpp:75:30:75:32 | overflowdest_test2 output argument | | overflowdestination.cpp:76:30:76:32 | src indirection | overflowdestination.cpp:57:52:57:54 | src indirection | nodes | main.cpp:6:27:6:30 | argv indirection | semmle.label | argv indirection | @@ -28,15 +34,20 @@ nodes | overflowdestination.cpp:43:8:43:10 | fgets output argument | semmle.label | fgets output argument | | overflowdestination.cpp:46:15:46:17 | src indirection | semmle.label | src indirection | | overflowdestination.cpp:50:52:50:54 | src indirection | semmle.label | src indirection | +| overflowdestination.cpp:53:9:53:12 | memcpy output argument | semmle.label | memcpy output argument | | overflowdestination.cpp:53:15:53:17 | src indirection | semmle.label | src indirection | | overflowdestination.cpp:53:15:53:17 | src indirection | semmle.label | src indirection | +| overflowdestination.cpp:54:9:54:12 | memcpy output argument | semmle.label | memcpy output argument | | overflowdestination.cpp:57:52:57:54 | src indirection | semmle.label | src indirection | | overflowdestination.cpp:64:16:64:19 | src2 indirection | semmle.label | src2 indirection | | overflowdestination.cpp:64:16:64:19 | src2 indirection | semmle.label | src2 indirection | | overflowdestination.cpp:73:8:73:10 | fgets output argument | semmle.label | fgets output argument | +| overflowdestination.cpp:75:30:75:32 | overflowdest_test2 output argument | semmle.label | overflowdest_test2 output argument | | overflowdestination.cpp:75:30:75:32 | src indirection | semmle.label | src indirection | | overflowdestination.cpp:76:30:76:32 | src indirection | semmle.label | src indirection | subpaths +| overflowdestination.cpp:75:30:75:32 | src indirection | overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:53:9:53:12 | memcpy output argument | overflowdestination.cpp:75:30:75:32 | overflowdest_test2 output argument | +| overflowdestination.cpp:75:30:75:32 | src indirection | overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:54:9:54:12 | memcpy output argument | overflowdestination.cpp:75:30:75:32 | overflowdest_test2 output argument | #select | overflowdestination.cpp:30:2:30:8 | call to strncpy | main.cpp:6:27:6:30 | argv indirection | overflowdestination.cpp:30:17:30:20 | arg1 indirection | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. | | overflowdestination.cpp:30:2:30:8 | call to strncpy | main.cpp:6:27:6:30 | argv indirection | overflowdestination.cpp:30:17:30:20 | arg1 indirection | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. | From 86dfc7b66e87b1877ddeb653195d59478685997a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 23 Jun 2023 08:18:06 +0200 Subject: [PATCH 294/364] python: format --- .../model-summaries/model_summaries.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py index 5074814f341..64909fcd741 100644 --- a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py +++ b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py @@ -54,8 +54,8 @@ SINK(via_reversed[0]) # $ flow="SOURCE, l:-1 -> via_reversed[0]" tainted_list = MS_reversed(TAINTED_LIST) ensure_tainted( tainted_list, # $ tainted - tainted_list[0] # $ tainted - ) + tainted_list[0], # $ tainted +) # Complex summaries def box(x): @@ -67,8 +67,8 @@ SINK(via_map[0][0]) # $ flow="SOURCE, l:-1 -> via_map[0][0]" tainted_mapped = MS_list_map(box, TAINTED_LIST) ensure_tainted( tainted_mapped, # $ tainted - tainted_mapped[0][0] # $ tainted - ) + tainted_mapped[0][0], # $ tainted +) def explicit_identity(x): return x @@ -79,8 +79,8 @@ SINK(via_map_explicit[0]) # $ flow="SOURCE, l:-1 -> via_map_explicit[0]" tainted_mapped_explicit = MS_list_map(explicit_identity, TAINTED_LIST) ensure_tainted( tainted_mapped_explicit, # $ tainted - tainted_mapped_explicit[0] # $ tainted - ) + tainted_mapped_explicit[0], # $ tainted +) via_map_summary = MS_list_map(MS_identity, [SOURCE]) SINK(via_map_summary[0]) # $ flow="SOURCE, l:-1 -> via_map_summary[0]" @@ -88,8 +88,8 @@ SINK(via_map_summary[0]) # $ flow="SOURCE, l:-1 -> via_map_summary[0]" tainted_mapped_summary = MS_list_map(MS_identity, TAINTED_LIST) ensure_tainted( tainted_mapped_summary, # $ tainted - tainted_mapped_summary[0] # $ tainted - ) + tainted_mapped_summary[0], # $ tainted +) via_append_el = MS_append_to_list([], SOURCE) SINK(via_append_el[0]) # $ flow="SOURCE, l:-1 -> via_append_el[0]" @@ -97,8 +97,8 @@ SINK(via_append_el[0]) # $ flow="SOURCE, l:-1 -> via_append_el[0]" tainted_list_el = MS_append_to_list([], TAINTED_STRING) ensure_tainted( tainted_list_el, # $ tainted - tainted_list_el[0] # $ tainted - ) + tainted_list_el[0], # $ tainted +) via_append = MS_append_to_list([SOURCE], NONSOURCE) SINK(via_append[0]) # $ flow="SOURCE, l:-1 -> via_append[0]" @@ -106,8 +106,8 @@ SINK(via_append[0]) # $ flow="SOURCE, l:-1 -> via_append[0]" tainted_list_implicit = MS_append_to_list(TAINTED_LIST, NONSOURCE) ensure_tainted( tainted_list, # $ tainted - tainted_list[0] # $ tainted - ) + tainted_list[0], # $ tainted +) # Modeled flow-summary is not value preserving from json import MS_loads as json_loads @@ -120,5 +120,5 @@ SINK_F(json_loads(SOURCE)[0]) tainted_resultlist = json_loads(TAINTED_STRING) ensure_tainted( tainted_resultlist, # $ tainted - tainted_resultlist[0] # $ tainted - ) + tainted_resultlist[0], # $ tainted +) From 79ee5112fc16923d5be20b28d6a94580260aba84 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 23 Jun 2023 09:41:02 +0200 Subject: [PATCH 295/364] Ruby: Add `toString` functionality consistency queries --- ruby/ql/consistency-queries/AstConsistency.ql | 5 +++++ ruby/ql/consistency-queries/CfgConsistency.ql | 6 ++++++ ruby/ql/consistency-queries/DataFlowConsistency.ql | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/ruby/ql/consistency-queries/AstConsistency.ql b/ruby/ql/consistency-queries/AstConsistency.ql index 8a5ebcdcda7..3a49d7cacc0 100644 --- a/ruby/ql/consistency-queries/AstConsistency.ql +++ b/ruby/ql/consistency-queries/AstConsistency.ql @@ -23,3 +23,8 @@ query predicate multipleParents(AstNode node, AstNode parent, string cls) { one != two ) } + +query predicate multipleToString(AstNode n, string s) { + s = strictconcat(n.toString(), ",") and + strictcount(n.toString()) > 1 +} diff --git a/ruby/ql/consistency-queries/CfgConsistency.ql b/ruby/ql/consistency-queries/CfgConsistency.ql index 8a5b311ca47..1961bbf7b3a 100644 --- a/ruby/ql/consistency-queries/CfgConsistency.ql +++ b/ruby/ql/consistency-queries/CfgConsistency.ql @@ -1,5 +1,6 @@ import codeql.ruby.controlflow.internal.ControlFlowGraphImplShared::Consistency import codeql.ruby.AST +import codeql.ruby.CFG import codeql.ruby.controlflow.internal.Completion import codeql.ruby.controlflow.internal.ControlFlowGraphImpl @@ -18,3 +19,8 @@ query predicate nonPostOrderExpr(Expr e, string cls) { c instanceof NormalCompletion ) } + +query predicate multipleToString(CfgNode n, string s) { + s = strictconcat(n.toString(), ",") and + strictcount(n.toString()) > 1 +} diff --git a/ruby/ql/consistency-queries/DataFlowConsistency.ql b/ruby/ql/consistency-queries/DataFlowConsistency.ql index fbfccce4bcb..46384305f7a 100644 --- a/ruby/ql/consistency-queries/DataFlowConsistency.ql +++ b/ruby/ql/consistency-queries/DataFlowConsistency.ql @@ -33,3 +33,8 @@ private class MyConsistencyConfiguration extends ConsistencyConfiguration { ) } } + +query predicate multipleToString(Node n, string s) { + s = strictconcat(n.toString(), ",") and + strictcount(n.toString()) > 1 +} From 26856a82a6320477d68a8002f3f9dd16982df935 Mon Sep 17 00:00:00 2001 From: yoff Date: Fri, 23 Jun 2023 10:15:20 +0200 Subject: [PATCH 296/364] Apply suggestions from code review Co-authored-by: Asger F --- .../javascript/frameworks/data/internal/ApiGraphModels.qll | 2 +- .../semmle/python/frameworks/data/internal/ApiGraphModels.qll | 2 +- .../lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index 6688ba36cd0..b33b9e8e238 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -644,7 +644,7 @@ module ModelOutput { } /** - * Holds if a `baseNode` is an invocation identified by the `type,path` part of a summary row. + * Holds if a `baseNode` is a callable identified by the `type,path` part of a summary row. */ cached predicate resolvedSummaryRefBase(string type, string path, API::Node baseNode) { diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll index 6688ba36cd0..b33b9e8e238 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -644,7 +644,7 @@ module ModelOutput { } /** - * Holds if a `baseNode` is an invocation identified by the `type,path` part of a summary row. + * Holds if a `baseNode` is a callable identified by the `type,path` part of a summary row. */ cached predicate resolvedSummaryRefBase(string type, string path, API::Node baseNode) { diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index 6688ba36cd0..b33b9e8e238 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -644,7 +644,7 @@ module ModelOutput { } /** - * Holds if a `baseNode` is an invocation identified by the `type,path` part of a summary row. + * Holds if a `baseNode` is a callable identified by the `type,path` part of a summary row. */ cached predicate resolvedSummaryRefBase(string type, string path, API::Node baseNode) { From 0cb27e7511f0ac24e79afcd029339ba9ac6331db Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 23 Jun 2023 13:28:11 +0200 Subject: [PATCH 297/364] C#: Add `toString` functionality consistency queries --- csharp/ql/consistency-queries/AstConsistency.qll | 5 +++++ csharp/ql/consistency-queries/CfgConsistency.ql | 5 +++++ csharp/ql/consistency-queries/DataFlowConsistency.ql | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/csharp/ql/consistency-queries/AstConsistency.qll b/csharp/ql/consistency-queries/AstConsistency.qll index 5373b638db7..3871cdf99f2 100644 --- a/csharp/ql/consistency-queries/AstConsistency.qll +++ b/csharp/ql/consistency-queries/AstConsistency.qll @@ -17,3 +17,8 @@ query predicate missingLocation(Element e) { not exists(TupleType t | e = t or e = t.getAField()) and not exists(e.getLocation()) } + +query predicate multipleToString(Element e, string s) { + s = strictconcat(e.toString(), ",") and + strictcount(e.toString()) > 1 +} diff --git a/csharp/ql/consistency-queries/CfgConsistency.ql b/csharp/ql/consistency-queries/CfgConsistency.ql index fe45e5a96d8..c50d7aaa101 100644 --- a/csharp/ql/consistency-queries/CfgConsistency.ql +++ b/csharp/ql/consistency-queries/CfgConsistency.ql @@ -62,3 +62,8 @@ query predicate preBasicBlockConsistency(ControlFlowElement cfe1, ControlFlowEle bbIntraSuccInconsistency(cfe1, cfe2) and s = "intra succ inconsistency" } + +query predicate multipleToString(Node n, string s) { + s = strictconcat(n.toString(), ",") and + strictcount(n.toString()) > 1 +} diff --git a/csharp/ql/consistency-queries/DataFlowConsistency.ql b/csharp/ql/consistency-queries/DataFlowConsistency.ql index f4c86ae3815..8f099fe6daf 100644 --- a/csharp/ql/consistency-queries/DataFlowConsistency.ql +++ b/csharp/ql/consistency-queries/DataFlowConsistency.ql @@ -74,3 +74,8 @@ private class MyConsistencyConfiguration extends ConsistencyConfiguration { override predicate identityLocalStepExclude(Node n) { none() } } + +query predicate multipleToString(Node n, string s) { + s = strictconcat(n.toString(), ",") and + strictcount(n.toString()) > 1 +} From f28aefad8bef09e0e73c94e922b61ce1634227e9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 23 Jun 2023 14:00:18 +0200 Subject: [PATCH 298/364] Ruby: Reduce string pool preasure by late-inlining `locationRelativePathToString` ``` [2023-06-23 13:48:23] Evaluated non-recursive predicate Sinatra#e09174a3::Sinatra::locationRelativePathToString#1#ff@683a25ce in 34682ms (size: 8048121). Evaluated relational algebra for predicate Sinatra#e09174a3::Sinatra::locationRelativePathToString#1#ff@683a25ce with tuple counts: 8048122 ~0% {6} r1 = SCAN locations_default OUTPUT In.1, In.0, toString(In.5), toString(In.2), toString(In.3), toString(In.4) 8048121 ~0% {2} r2 = JOIN r1 WITH FileSystem#df18ed9a::Make#FileSystem#e91ad87f::Input#::Container::getRelativePath#0#dispred#ff ON FIRST 1 OUTPUT Lhs.1, (Rhs.1 ++ "@" ++ Lhs.3 ++ ":" ++ Lhs.4 ++ ":" ++ Lhs.5 ++ ":" ++ Lhs.2) return r2 ``` --- .../ql/lib/codeql/ruby/frameworks/Sinatra.qll | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Sinatra.qll b/ruby/ql/lib/codeql/ruby/frameworks/Sinatra.qll index 4b4f1bbd404..ef9a9392527 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Sinatra.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Sinatra.qll @@ -105,15 +105,25 @@ module Sinatra { * Gets the template file referred to by `erbCall`. * This works on the AST level to avoid non-monotonic reecursion in `ErbLocalsHashSyntheticGlobal`. */ + pragma[nomagic] private ErbFile getTemplateFile(MethodCall erbCall) { erbCall.getMethodName() = "erb" and result.getTemplateName() = erbCall.getArgument(0).getConstantValue().getStringlikeValue() and result.getRelativePath().matches("%views/%") } + pragma[nomagic] + private predicate erbCallAtLocation(MethodCall erbCall, ErbFile erbFile, Location l) { + erbCall.getMethodName() = "erb" and + erbFile = getTemplateFile(erbCall) and + l = erbCall.getLocation() + } + /** * Like `Location.toString`, but displays the relative path rather than the full path. */ + bindingset[loc] + pragma[inline_late] private string locationRelativePathToString(Location loc) { result = loc.getFile().getRelativePath() + "@" + loc.getStartLine() + ":" + loc.getStartColumn() + ":" + @@ -121,7 +131,7 @@ module Sinatra { } /** - * A synthetic global representing the hash of local variables passed to an ERB template. + * A synthetic global representing the hash of local variables passed to an ERB template. */ class ErbLocalsHashSyntheticGlobal extends SummaryComponent::SyntheticGlobal { private string id; @@ -129,10 +139,11 @@ module Sinatra { private ErbFile erbFile; ErbLocalsHashSyntheticGlobal() { - this = "SinatraErbLocalsHash(" + id + ")" and - id = erbFile.getRelativePath() + "," + locationRelativePathToString(erbCall.getLocation()) and - erbCall.getMethodName() = "erb" and - erbFile = getTemplateFile(erbCall) + exists(Location l | + erbCallAtLocation(erbCall, erbFile, l) and + id = erbFile.getRelativePath() + "," + locationRelativePathToString(l) and + this = "SinatraErbLocalsHash(" + id + ")" + ) } /** From 5da377b46a9dc0b8c7dcec3939278c6006030608 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Fri, 23 Jun 2023 13:51:35 +0100 Subject: [PATCH 299/364] Kotlin: Build: Remove some dead code --- java/kotlin-extractor/build.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/java/kotlin-extractor/build.py b/java/kotlin-extractor/build.py index 2735f6af1c1..009017b0073 100755 --- a/java/kotlin-extractor/build.py +++ b/java/kotlin-extractor/build.py @@ -133,30 +133,6 @@ def find_sources(path): return glob.glob(path + '/**/*.kt', recursive=True) + glob.glob(path + '/**/*.java', recursive=True) -def get_kotlin_lib_folder(): - x = run_process([kotlinc, '-version', '-verbose'], capture_output=True) - output = x.stderr.decode(encoding='UTF-8', errors='strict') - m = re.match( - r'.*\nlogging: using Kotlin home directory ([^\n]+)\n.*', output) - if m is None: - raise Exception('Cannot determine kotlinc home directory') - kotlin_home = m.group(1) - print("Kotlin home directory: " + kotlin_home) - return kotlin_home + '/lib' - - -def get_gradle_lib_folder(): - x = run_process(['gradle', 'getHomeDir'], capture_output=True) - output = x.stdout.decode(encoding='UTF-8', errors='strict') - m = re.search(r'(?m)^> Task :getHomeDir\n([^\n]+)$', output) - if m is None: - print("gradle getHomeDir output:\n" + output, file=sys.stderr) - raise Exception('Cannot determine gradle home directory') - gradle_home = m.group(1) - print("Gradle home directory: " + gradle_home) - return gradle_home + '/lib' - - def find_jar(path, base): fn = path + '/' + base + '.jar' if not os.path.isfile(fn): From 8f69b2afa885335119c76f44e14635d1fbc956a3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 23 Jun 2023 14:00:59 +0100 Subject: [PATCH 300/364] Swift: Add some test cases aimed at regex parsing correctness. --- .../test/library-tests/regex/parse.expected | 102 ++++++++++++++++++ swift/ql/test/library-tests/regex/regex.swift | 23 ++++ 2 files changed, 125 insertions(+) diff --git a/swift/ql/test/library-tests/regex/parse.expected b/swift/ql/test/library-tests/regex/parse.expected index 007337ca05b..34c746bf94d 100644 --- a/swift/ql/test/library-tests/regex/parse.expected +++ b/swift/ql/test/library-tests/regex/parse.expected @@ -6381,3 +6381,105 @@ regex.swift: # 172| [RegExpConstant, RegExpNormalChar] # 172| bb + +# 180| [RegExpCharacterClass] [a-z] +#-----| 0 -> [RegExpCharacterRange] a-z + +# 180| [RegExpConstant, RegExpNormalChar] a + +# 180| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 180| [RegExpConstant, RegExpNormalChar] z + +# 181| [RegExpCharacterClass] [a-zA-Z] +#-----| 0 -> [RegExpCharacterRange] a-z +#-----| 1 -> [RegExpCharacterRange] A-Z + +# 181| [RegExpConstant, RegExpNormalChar] a + +# 181| [RegExpCharacterRange] a-z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] z + +# 181| [RegExpConstant, RegExpNormalChar] z + +# 181| [RegExpConstant, RegExpNormalChar] A + +# 181| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 181| [RegExpConstant, RegExpNormalChar] Z + +# 184| [RegExpCharacterClass] [a-] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + +# 184| [RegExpConstant, RegExpNormalChar] a + +# 184| [RegExpConstant, RegExpNormalChar] - + +# 185| [RegExpCharacterClass] [-a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] - +#-----| 1 -> [RegExpConstant, RegExpNormalChar] a + +# 185| [RegExpConstant, RegExpNormalChar] - + +# 185| [RegExpConstant, RegExpNormalChar] a + +# 186| [RegExpCharacterClass] [-] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] - + +# 186| [RegExpConstant, RegExpNormalChar] - + +# 187| [RegExpCharacterClass] [*] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] * + +# 187| [RegExpConstant, RegExpNormalChar] * + +# 188| [RegExpCharacterClass] [^a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 188| [RegExpConstant, RegExpNormalChar] a + +# 189| [RegExpCharacterClass] [a^] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] ^ + +# 189| [RegExpConstant, RegExpNormalChar] a + +# 189| [RegExpConstant, RegExpNormalChar] ^ + +# 190| [RegExpCharacterClass] [\\] +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ + +# 190| [RegExpConstant, RegExpEscape] \\ + +# 191| [RegExpCharacterClass] [\\\]] +#-----| 0 -> [RegExpConstant, RegExpEscape] \\ +#-----| 1 -> [RegExpConstant, RegExpEscape] \] + +# 191| [RegExpConstant, RegExpEscape] \\ + +# 191| [RegExpConstant, RegExpEscape] \] + +# 192| [RegExpCharacterClass] [:] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] : + +# 192| [RegExpConstant, RegExpNormalChar] : + +# 193| [RegExpNamedCharacterProperty] [:digit:] + +# 194| [RegExpNamedCharacterProperty] [:alnum:] + +# 197| [RegExpCharacterClass] []a] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] a + +# 197| [RegExpConstant, RegExpNormalChar] ] + +# 197| [RegExpConstant, RegExpNormalChar] a + +# 198| [RegExpNamedCharacterProperty] [:aaaaa:] diff --git a/swift/ql/test/library-tests/regex/regex.swift b/swift/ql/test/library-tests/regex/regex.swift index ab372df9ffc..f48e8e0dc7d 100644 --- a/swift/ql/test/library-tests/regex/regex.swift +++ b/swift/ql/test/library-tests/regex/regex.swift @@ -173,4 +173,27 @@ func myRegexpMethodsTests(b: Bool, str_unknown: String) throws { aa| bb """).firstMatch(in: input) // $ input=input regex=aa|NEWLINEbb + + // --- exploring parser correctness --- + + // ranges + _ = try Regex("[a-z]").firstMatch(in: input) // $ input=input regex=[a-z] + _ = try Regex("[a-zA-Z]").firstMatch(in: input) // $ input=input regex=[a-zA-Z] + + // character classes + _ = try Regex("[a-]").firstMatch(in: input) // $ input=input regex=[a-] + _ = try Regex("[-a]").firstMatch(in: input) // $ input=input regex=[-a] + _ = try Regex("[-]").firstMatch(in: input) // $ input=input regex=[-] + _ = try Regex("[*]").firstMatch(in: input) // $ input=input regex=[*] + _ = try Regex("[^a]").firstMatch(in: input) // $ input=input regex=[^a] + _ = try Regex("[a^]").firstMatch(in: input) // $ input=input regex=[a^] + _ = try Regex(#"[\\]"#).firstMatch(in: input) // $ input=input regex=[\\] + _ = try Regex(#"[\\\]]"#).firstMatch(in: input) // $ input=input regex=[\\\]] + _ = try Regex("[:]").firstMatch(in: input) // $ input=input regex=[:] + _ = try Regex("[:digit:]").firstMatch(in: input) // $ input=input regex=[:digit:] SPURIOUS: $hasParseFailure + _ = try Regex("[:alnum:]").firstMatch(in: input) // $ input=input regex=[:alnum:] SPURIOUS: $hasParseFailure + + // invalid (Swift doesn't like these regexs) + _ = try Regex("[]a]").firstMatch(in: input) // this is valid in other regex implementations, and is likely harmless to accept + _ = try Regex("[:aaaaa:]").firstMatch(in: input) // $ hasParseFailure } From 987ca61ef58dbf0afa47804cbff14cece778f110 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 23 Jun 2023 13:01:26 +0100 Subject: [PATCH 301/364] Swift: Fix typo in a comment. --- swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll index fb4ff566d9f..7a837cd733e 100644 --- a/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll +++ b/swift/ql/lib/codeql/swift/regex/internal/ParseRegex.qll @@ -98,7 +98,7 @@ abstract class RegExp extends Expr { pos = rank[index](int p | (this.nonEscapedCharAt(p) = "[" or this.nonEscapedCharAt(p) = "]") and - // Brackets that art part of POSIX expressions should not count as + // Brackets that are part of POSIX expressions should not count as // char-set delimiters. not exists(int x, int y | this.posixStyleNamedCharacterProperty(x, y, _) and pos >= x and pos < y @@ -121,7 +121,9 @@ abstract class RegExp extends Expr { ) } - /** Whether there is a character class, between start (inclusive) and end (exclusive). */ + /** + * Whether there is a character class, between start (inclusive) and end (exclusive). + */ predicate charSet(int start, int end) { exists(int innerStart, int innerEnd | this.charSetStart(start, innerStart) and From 5cffa59476a530f825e663dfff38bb4be00a7340 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 23 Jun 2023 14:33:25 +0100 Subject: [PATCH 302/364] Swift: Make the RegexEval interface cleaner. --- swift/ql/lib/codeql/swift/regex/Regex.qll | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/swift/ql/lib/codeql/swift/regex/Regex.qll b/swift/ql/lib/codeql/swift/regex/Regex.qll index e92a7a25114..b97847a1ac6 100644 --- a/swift/ql/lib/codeql/swift/regex/Regex.qll +++ b/swift/ql/lib/codeql/swift/regex/Regex.qll @@ -60,18 +60,15 @@ private class ParsedStringRegex extends RegExp, StringLiteralExpr { * ``` */ abstract class RegexEval extends CallExpr { - Expr regexInput; - Expr stringInput; - /** * Gets the input to this call that is the regular expression being evaluated. */ - Expr getRegexInput() { result = regexInput } + abstract Expr getRegexInput(); /** * Gets the input to this call that is the string the regular expression is evaluated on. */ - Expr getStringInput() { result = stringInput } + abstract Expr getStringInput(); /** * Gets a regular expression value that is evaluated here (if any can be identified). @@ -83,6 +80,9 @@ abstract class RegexEval extends CallExpr { * A call to a function that always evaluates a regular expression. */ private class AlwaysRegexEval extends RegexEval { + Expr regexInput; + Expr stringInput; + AlwaysRegexEval() { this.getStaticTarget() .(Method) @@ -127,4 +127,8 @@ private class AlwaysRegexEval extends RegexEval { regexInput = this.getArgument(0).getExpr() and stringInput = this.getQualifier() } + + override Expr getRegexInput() { result = regexInput } + + override Expr getStringInput() { result = stringInput } } From b6e4ba6f9d33d6a53daea193f68977ec2553ad35 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Fri, 23 Jun 2023 18:19:43 +0200 Subject: [PATCH 303/364] Add `SerialKiller` model --- .../security/UnsafeDeserializationQuery.qll | 18 ++++++++++++--- ...-02-unsafe-deserialization-serialkiller.md | 4 ++++ .../test/query-tests/security/CWE-502/A.java | 7 ++++++ .../test/query-tests/security/CWE-502/options | 2 +- .../org/nibblesec/tools/SerialKiller.java | 23 +++++++++++++++++++ 5 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 java/ql/src/change-notes/2023-06-02-unsafe-deserialization-serialkiller.md create mode 100644 java/ql/test/stubs/serialkiller-4.0.0/org/nibblesec/tools/SerialKiller.java diff --git a/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll b/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll index 7e995e5cbaf..ee553c5f7bd 100644 --- a/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll +++ b/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll @@ -28,6 +28,20 @@ private class ObjectInputStreamReadObjectMethod extends Method { } } +/** + * A type coming from `ObjectInputStream` that makes it safe to deserialize untrusted data. + * + * * See https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/serialization/ValidatingObjectInputStream.html + * * See https://github.com/ikkisoft/SerialKiller + */ +private class SafeObjectInputStreamType extends RefType { + SafeObjectInputStreamType() { + this.getASourceSupertype*() + .hasQualifiedName("org.apache.commons.io.serialization", "ValidatingObjectInputStream") or + this.getASourceSupertype*().hasQualifiedName("org.nibblesec.tools", "SerialKiller") + } +} + private class XmlDecoderReadObjectMethod extends Method { XmlDecoderReadObjectMethod() { this.getDeclaringType().hasQualifiedName("java.beans", "XMLDecoder") and @@ -135,9 +149,7 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) { sink = ma.getQualifier() and not exists(DataFlow::ExprNode node | node.getExpr() = sink and - node.getTypeBound() - .(RefType) - .hasQualifiedName("org.apache.commons.io.serialization", "ValidatingObjectInputStream") + node.getTypeBound() instanceof SafeObjectInputStreamType ) or m instanceof XmlDecoderReadObjectMethod and diff --git a/java/ql/src/change-notes/2023-06-02-unsafe-deserialization-serialkiller.md b/java/ql/src/change-notes/2023-06-02-unsafe-deserialization-serialkiller.md new file mode 100644 index 00000000000..588e83d4795 --- /dev/null +++ b/java/ql/src/change-notes/2023-06-02-unsafe-deserialization-serialkiller.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The query `java/unsafe-deserialization` has been updated to take into account `SerialKiller`, a library used to prevent deserialization of arbitrary classes. \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-502/A.java b/java/ql/test/query-tests/security/CWE-502/A.java index e95f15bff4f..f3bd633f880 100644 --- a/java/ql/test/query-tests/security/CWE-502/A.java +++ b/java/ql/test/query-tests/security/CWE-502/A.java @@ -7,6 +7,7 @@ import com.esotericsoftware.kryo.io.Input; import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.Yaml; +import org.nibblesec.tools.SerialKiller; public class A { public Object deserialize1(Socket sock) throws java.io.IOException, ClassNotFoundException { @@ -21,6 +22,12 @@ public class A { return in.readUnshared(); // $unsafeDeserialization } + public Object deserializeWithSerialKiller(Socket sock) throws java.io.IOException, ClassNotFoundException { + InputStream inputStream = sock.getInputStream(); + ObjectInputStream in = new SerialKiller(inputStream, "/etc/serialkiller.conf"); + return in.readUnshared(); // OK + } + public Object deserialize3(Socket sock) throws java.io.IOException { InputStream inputStream = sock.getInputStream(); XMLDecoder d = new XMLDecoder(inputStream); diff --git a/java/ql/test/query-tests/security/CWE-502/options b/java/ql/test/query-tests/security/CWE-502/options index 0e9cab2d100..47e25fe74fb 100644 --- a/java/ql/test/query-tests/security/CWE-502/options +++ b/java/ql/test/query-tests/security/CWE-502/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/jabsorb-1.3.2:${testdir}/../../../stubs/json-java-20210307:${testdir}/../../../stubs/joddjson-6.0.3:${testdir}/../../../stubs/flexjson-2.1:${testdir}/../../../stubs/gson-2.8.6:${testdir}/../../../stubs/google-android-9.0.0 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/jabsorb-1.3.2:${testdir}/../../../stubs/json-java-20210307:${testdir}/../../../stubs/joddjson-6.0.3:${testdir}/../../../stubs/flexjson-2.1:${testdir}/../../../stubs/gson-2.8.6:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/serialkiller-4.0.0 diff --git a/java/ql/test/stubs/serialkiller-4.0.0/org/nibblesec/tools/SerialKiller.java b/java/ql/test/stubs/serialkiller-4.0.0/org/nibblesec/tools/SerialKiller.java new file mode 100644 index 00000000000..fc59ccd538d --- /dev/null +++ b/java/ql/test/stubs/serialkiller-4.0.0/org/nibblesec/tools/SerialKiller.java @@ -0,0 +1,23 @@ +/* + * SerialKiller.java + * + * Copyright (c) 2015-2016 Luca Carettoni + * + * SerialKiller is an easy-to-use look-ahead Java deserialization library + * to secure application from untrusted input. When Java serialization is + * used to exchange information between a client and a server, attackers + * can replace the legitimate serialized stream with malicious data. + * SerialKiller inspects Java classes during naming resolution and allows + * a combination of blacklisting/whitelisting to secure your application. + * + * Dual-Licensed Software: Apache v2.0 and GPL v2.0 + */ +package org.nibblesec.tools; + +import java.io.ObjectInputStream; +import java.io.InputStream; +import java.io.IOException; + +public class SerialKiller extends ObjectInputStream { + public SerialKiller(InputStream inputStream, String configFile) throws IOException {} +} \ No newline at end of file From 2dc4f23dbbc311bde84bacbcc71d5ff217892264 Mon Sep 17 00:00:00 2001 From: jorgectf Date: Fri, 23 Jun 2023 19:34:21 +0200 Subject: [PATCH 304/364] Add models for `org.apache.commons.lang` --- .../org.apache.commons.lang.model.yml | 1695 +++++++++++++++++ .../2023-06-23-apache-commons-lang.md | 4 + 2 files changed, 1699 insertions(+) create mode 100644 java/ql/lib/ext/generated/org.apache.commons.lang.model.yml create mode 100644 java/ql/src/change-notes/2023-06-23-apache-commons-lang.md diff --git a/java/ql/lib/ext/generated/org.apache.commons.lang.model.yml b/java/ql/lib/ext/generated/org.apache.commons.lang.model.yml new file mode 100644 index 00000000000..56f9c251388 --- /dev/null +++ b/java/ql/lib/ext/generated/org.apache.commons.lang.model.yml @@ -0,0 +1,1695 @@ +# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT. +# Definitions of models for the org.apache.commons.lang framework. + +extensions: + - addsTo: + pack: codeql/java-all + extensible: summaryModel + data: + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(Object,Object)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(Object,Object,Comparator)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(Object[],Object[])", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(Object[],Object[],Comparator)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(boolean,boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(boolean[],boolean[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(byte,byte)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(byte[],byte[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(char,char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(char[],char[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(double,double)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(double[],double[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(float,float)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(float[],float[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(int,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(int[],int[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(long,long)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(long[],long[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(short,short)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "append", "(short[],short[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", true, "appendSuper", "(int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(Object,Object)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(Object[],Object[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(boolean,boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(boolean[],boolean[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(byte,byte)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(byte[],byte[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(char,char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(char[],char[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(double,double)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(double[],double[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(float,float)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(float[],float[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(int,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(int[],int[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(long,long)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(long[],long[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(short,short)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "append", "(short[],short[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", true, "appendSuper", "(boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(Object)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(Object[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(boolean[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(byte)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(byte[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(char[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(double)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(double[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(float)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(float[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(int[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(long)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(long[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(short)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "append", "(short[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", true, "appendSuper", "(int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer)", "", "Argument[1]", "Argument[2]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer,Class,boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer,Class,boolean)", "", "Argument[1]", "Argument[2]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer,Class,boolean)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer,Class,boolean)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer,Class,boolean,boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer,Class,boolean,boolean)", "", "Argument[1]", "Argument[2]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer,Class,boolean,boolean)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "ReflectionToStringBuilder", "(Object,ToStringStyle,StringBuffer,Class,boolean,boolean)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "getExcludeFieldNames", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "reflectionAppendArray", "(Object)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "setExcludeFieldNames", "(String[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "ToStringBuilder", "(Object)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "ToStringBuilder", "(Object,ToStringStyle)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "ToStringBuilder", "(Object,ToStringStyle)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "ToStringBuilder", "(Object,ToStringStyle,StringBuffer)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "ToStringBuilder", "(Object,ToStringStyle,StringBuffer)", "", "Argument[1]", "Argument[2]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "ToStringBuilder", "(Object,ToStringStyle,StringBuffer)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "ToStringBuilder", "(Object,ToStringStyle,StringBuffer)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(Object)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(Object)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(Object[])", "", "Argument[0].ArrayElement", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(Object[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object,boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object,boolean)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object,boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object[])", "", "Argument[1].ArrayElement", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object[],boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object[],boolean)", "", "Argument[1].ArrayElement", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,Object[],boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,boolean[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,boolean[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,boolean[],boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,boolean[],boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,byte)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,byte)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,byte[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,byte[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,byte[],boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,byte[],boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,char)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,char[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,char[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,char[],boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,char[],boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,double)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,double)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,double[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,double[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,double[],boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,double[],boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,float)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,float)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,float[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,float[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,float[],boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,float[],boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,int)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,int[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,int[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,int[],boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,int[],boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,long)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,long)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,long[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,long[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,long[],boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,long[],boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,short)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,short)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,short[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,short[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,short[],boolean)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(String,short[],boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(boolean[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(byte)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(byte[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(char[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(double)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(double[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(float)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(float[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(int[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(long)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(long[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(short)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "append", "(short[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "appendAsObjectToString", "(Object)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "appendSuper", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "appendSuper", "(String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "appendToString", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "appendToString", "(String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "getObject", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "getStringBuffer", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "getStyle", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,Object,Boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,Object,Boolean)", "", "Argument[2]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,Object,Boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,Object[],Boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,Object[],Boolean)", "", "Argument[2].ArrayElement", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,Object[],Boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,boolean[],Boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,boolean[],Boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,byte)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,byte)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,byte[],Boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,byte[],Boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,char)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,char)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,char[],Boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,char[],Boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,double)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,double)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,double[],Boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,double[],Boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,float)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,float)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,float[],Boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,float[],Boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,int)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,int)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,int[],Boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,int[],Boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,long)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,long)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,long[],Boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,long[],Boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,short)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,short)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,short[],Boolean)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "append", "(StringBuffer,String,short[],Boolean)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "appendEnd", "(StringBuffer,Object)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "appendStart", "(StringBuffer,Object)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "appendSuper", "(StringBuffer,String)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "appendSuper", "(StringBuffer,String)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "appendToString", "(StringBuffer,String)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "appendToString", "(StringBuffer,String)", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getArrayEnd", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getArraySeparator", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getArrayStart", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getContentEnd", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getContentStart", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getFieldNameValueSeparator", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getFieldSeparator", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getNullText", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getSizeEndText", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getSizeStartText", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getSummaryObjectEndText", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "getSummaryObjectStartText", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setArrayEnd", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setArraySeparator", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setArrayStart", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setContentEnd", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setContentStart", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setFieldNameValueSeparator", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setFieldSeparator", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setNullText", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setSizeEndText", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setSizeStartText", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setSummaryObjectEndText", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", true, "setSummaryObjectStartText", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.enums", "Enum", true, "getName", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.enums", "Enum", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.enums", "ValuedEnum", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", true, "getCause", "(Throwable)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", true, "getCause", "(Throwable,String[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", true, "getMessage", "(Throwable)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", true, "getRootCause", "(Throwable)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", true, "getRootCauseMessage", "(Throwable)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", true, "getRootCauseStackTrace", "(Throwable)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", true, "getThrowableList", "(Throwable)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", true, "getThrowables", "(Throwable)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", true, "getCause", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", true, "getMessage", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", true, "getMessage", "(int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", true, "getThrowable", "(int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", true, "getThrowables", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", true, "NestableDelegate", "(Nestable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", true, "getMessage", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", true, "getMessage", "(int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", true, "getMessages", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", true, "getThrowable", "(int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", true, "getThrowables", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableError", true, "NestableError", "(String,Throwable)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableError", true, "NestableError", "(Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableException", true, "NestableException", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableException", true, "NestableException", "(String,Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableException", true, "NestableException", "(String,Throwable)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableException", true, "NestableException", "(Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableRuntimeException", true, "NestableRuntimeException", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableRuntimeException", true, "NestableRuntimeException", "(String,Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableRuntimeException", true, "NestableRuntimeException", "(String,Throwable)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableRuntimeException", true, "NestableRuntimeException", "(Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.math", "DoubleRange", false, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.math", "FloatRange", false, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", false, "abs", "()", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", false, "pow", "(int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", false, "reduce", "()", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.math", "IntRange", false, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.math", "LongRange", false, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.math", "NumberRange", false, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.mutable", "Mutable", true, "getValue", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.mutable", "Mutable", true, "setValue", "(Object)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableObject", true, "MutableObject", "(Object)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.reflect", "ConstructorUtils", true, "getAccessibleConstructor", "(Constructor)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", true, "getAccessibleMethod", "(Method)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "CompositeFormat", true, "CompositeFormat", "(Format,Format)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "CompositeFormat", true, "CompositeFormat", "(Format,Format)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "CompositeFormat", true, "getFormatter", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "CompositeFormat", true, "getParser", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "ExtendedMessageFormat", true, "ExtendedMessageFormat", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "ExtendedMessageFormat", true, "ExtendedMessageFormat", "(String,Locale)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "ExtendedMessageFormat", true, "ExtendedMessageFormat", "(String,Locale,Map)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "ExtendedMessageFormat", true, "ExtendedMessageFormat", "(String,Locale,Map)", "", "Argument[2].Element", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "ExtendedMessageFormat", true, "ExtendedMessageFormat", "(String,Map)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "ExtendedMessageFormat", true, "ExtendedMessageFormat", "(String,Map)", "", "Argument[1].Element", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "StrBuilder", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(Object)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(StrBuilder)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(StrBuilder)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(StrBuilder,int,int)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(StrBuilder,int,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(String,int,int)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(String,int,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(StringBuffer)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(StringBuffer)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(StringBuffer,int,int)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(StringBuffer,int,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(char[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(char[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(char[],int,int)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(char[],int,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(double)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(float)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "append", "(long)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendAll", "(Collection)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendAll", "(Iterator)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendAll", "(Object[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendFixedWidthPadLeft", "(Object,int,char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendFixedWidthPadLeft", "(int,int,char)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendFixedWidthPadRight", "(Object,int,char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendFixedWidthPadRight", "(int,int,char)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendNewLine", "()", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendNull", "()", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendPadding", "(int,char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendSeparator", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendSeparator", "(String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendSeparator", "(String,int)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendSeparator", "(String,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendSeparator", "(char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendSeparator", "(char,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendWithSeparators", "(Collection,String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendWithSeparators", "(Collection,String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendWithSeparators", "(Iterator,String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendWithSeparators", "(Iterator,String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendWithSeparators", "(Object[],String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendWithSeparators", "(Object[],String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendln", "(Object)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendln", "(boolean)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendln", "(char)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendln", "(double)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendln", "(float)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendln", "(int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "appendln", "(long)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "clear", "()", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "delete", "(int,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "deleteAll", "(StrMatcher)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "deleteAll", "(String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "deleteAll", "(char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "deleteCharAt", "(int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "deleteFirst", "(StrMatcher)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "deleteFirst", "(String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "deleteFirst", "(char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "ensureCapacity", "(int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "getChars", "(char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "getChars", "(char[])", "", "Argument[this]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "getChars", "(char[])", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "getChars", "(int,int,char[],int)", "", "Argument[this]", "Argument[2]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "getNewLineText", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "getNullText", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,Object)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,char[])", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,char[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,char[],int,int)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,char[],int,int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,double)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,float)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "insert", "(int,long)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "leftString", "(int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "midString", "(int,int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "minimizeCapacity", "()", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replace", "(StrMatcher,String,int,int,int)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replace", "(StrMatcher,String,int,int,int)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replace", "(StrMatcher,String,int,int,int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replace", "(int,int,String)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replace", "(int,int,String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceAll", "(StrMatcher,String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceAll", "(StrMatcher,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceAll", "(StrMatcher,String)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceAll", "(String,String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceAll", "(String,String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceAll", "(char,char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceFirst", "(StrMatcher,String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceFirst", "(StrMatcher,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceFirst", "(StrMatcher,String)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceFirst", "(String,String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceFirst", "(String,String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "replaceFirst", "(char,char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "reverse", "()", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "rightString", "(int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "setCharAt", "(int,char)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "setLength", "(int)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "setNewLineText", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "setNewLineText", "(String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "setNullText", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "setNullText", "(String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "substring", "(int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "substring", "(int,int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "toCharArray", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "toCharArray", "(int,int)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "toStringBuffer", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", true, "trim", "()", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrLookup", true, "mapLookup", "(Map)", "", "Argument[0].Element", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", true, "charSetMatcher", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", true, "charSetMatcher", "(char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", true, "stringMatcher", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(Map)", "", "Argument[0].Element", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(Map,String,String)", "", "Argument[0].Element", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(Map,String,String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(Map,String,String)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(Map,String,String,char)", "", "Argument[0].Element", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(Map,String,String,char)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(Map,String,String,char)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(StrLookup)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(StrLookup,StrMatcher,StrMatcher,char)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(StrLookup,StrMatcher,StrMatcher,char)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(StrLookup,StrMatcher,StrMatcher,char)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(StrLookup,String,String,char)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(StrLookup,String,String,char)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "StrSubstitutor", "(StrLookup,String,String,char)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "getVariablePrefixMatcher", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "getVariableResolver", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "getVariableSuffixMatcher", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "replace", "(StrBuilder)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "replace", "(StrBuilder,int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "replace", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "replace", "(String,int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "replace", "(StringBuffer)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "replace", "(StringBuffer,int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "replace", "(char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "replace", "(char[],int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariablePrefix", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariablePrefix", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariablePrefix", "(String)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariablePrefix", "(char)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariablePrefixMatcher", "(StrMatcher)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariablePrefixMatcher", "(StrMatcher)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariableResolver", "(StrLookup)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariableSuffix", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariableSuffix", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariableSuffix", "(String)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariableSuffix", "(char)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariableSuffixMatcher", "(StrMatcher)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", true, "setVariableSuffixMatcher", "(StrMatcher)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(String,StrMatcher)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(String,StrMatcher)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(String,StrMatcher,StrMatcher)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(String,StrMatcher,StrMatcher)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(String,StrMatcher,StrMatcher)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(String,String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(String,String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(String,char)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(String,char,char)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(char[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(char[],StrMatcher)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(char[],StrMatcher)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(char[],StrMatcher,StrMatcher)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(char[],StrMatcher,StrMatcher)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(char[],StrMatcher,StrMatcher)", "", "Argument[2]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(char[],String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(char[],String)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(char[],char)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "StrTokenizer", "(char[],char,char)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getCSVInstance", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getCSVInstance", "(char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getContent", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getDelimiterMatcher", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getIgnoredMatcher", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getQuoteMatcher", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getTSVInstance", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getTSVInstance", "(char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getTokenArray", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getTokenList", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "getTrimmerMatcher", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "nextToken", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "previousToken", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "reset", "()", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "reset", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "reset", "(String)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "reset", "(char[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "reset", "(char[])", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setDelimiterChar", "(char)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setDelimiterMatcher", "(StrMatcher)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setDelimiterMatcher", "(StrMatcher)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setDelimiterString", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setDelimiterString", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setDelimiterString", "(String)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setEmptyTokenAsNull", "(boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setIgnoreEmptyTokens", "(boolean)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setIgnoredChar", "(char)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setIgnoredMatcher", "(StrMatcher)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setIgnoredMatcher", "(StrMatcher)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setQuoteChar", "(char)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setQuoteMatcher", "(StrMatcher)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setQuoteMatcher", "(StrMatcher)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setTrimmerMatcher", "(StrMatcher)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "setTrimmerMatcher", "(StrMatcher)", "", "Argument[this]", "ReturnValue", "value", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", true, "iterator", "(Calendar,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", true, "iterator", "(Object,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", true, "round", "(Calendar,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", true, "truncate", "(Calendar,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "format", "(Calendar,StringBuffer)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "format", "(Date,StringBuffer)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "format", "(long,StringBuffer)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getDateInstance", "(int,Locale)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getDateInstance", "(int,TimeZone)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getDateInstance", "(int,TimeZone,Locale)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getDateInstance", "(int,TimeZone,Locale)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getDateTimeInstance", "(int,int,Locale)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getDateTimeInstance", "(int,int,TimeZone)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getDateTimeInstance", "(int,int,TimeZone,Locale)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getDateTimeInstance", "(int,int,TimeZone,Locale)", "", "Argument[3]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getInstance", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getInstance", "(String,Locale)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getInstance", "(String,Locale)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getInstance", "(String,TimeZone)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getInstance", "(String,TimeZone)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getInstance", "(String,TimeZone,Locale)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getInstance", "(String,TimeZone,Locale)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getInstance", "(String,TimeZone,Locale)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getLocale", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getPattern", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getTimeInstance", "(int,Locale)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getTimeInstance", "(int,TimeZone)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getTimeInstance", "(int,TimeZone,Locale)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getTimeInstance", "(int,TimeZone,Locale)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "getTimeZone", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "add", "(Object[],Object)", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "add", "(Object[],Object)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "add", "(Object[],int,Object)", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "add", "(byte[],byte)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "add", "(byte[],int,byte)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "add", "(char[],char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "add", "(char[],int,char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "addAll", "(Object[],Object[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "addAll", "(Object[],Object[])", "", "Argument[1].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "addAll", "(byte[],byte[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "addAll", "(byte[],byte[])", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "addAll", "(char[],char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "addAll", "(char[],char[])", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "clone", "(Object[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "clone", "(byte[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "clone", "(char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "remove", "(Object[],int)", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "remove", "(byte[],int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "remove", "(char[],int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "removeElement", "(Object[],Object)", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "removeElement", "(byte[],byte)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "removeElement", "(char[],char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "subarray", "(Object[],int,int)", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "subarray", "(byte[],int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "subarray", "(char[],int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "toMap", "(Object[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "toString", "(Object)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "toString", "(Object,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", true, "toString", "(Object,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", true, "toString", "(Boolean,String,String,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", true, "toString", "(Boolean,String,String,String)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", true, "toString", "(Boolean,String,String,String)", "", "Argument[3]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", true, "toString", "(boolean,String,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", true, "toString", "(boolean,String,String)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "CharRange", false, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "CharSet", true, "getCharRanges", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "CharSetUtils", true, "delete", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "CharSetUtils", true, "delete", "(String,String[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "CharSetUtils", true, "squeeze", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "CharSetUtils", true, "squeeze", "(String,String[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "CharSetUtils", true, "translate", "(String,String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", true, "getPackageCanonicalName", "(Object,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", true, "getPackageCanonicalName", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", true, "getPackageName", "(Object,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", true, "getPackageName", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", true, "getShortCanonicalName", "(Object,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", true, "getShortCanonicalName", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", true, "getShortClassName", "(Object,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", true, "getShortClassName", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", true, "primitivesToWrappers", "(Class[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", true, "wrappersToPrimitives", "(Class[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "IllegalClassException", true, "IllegalClassException", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "IncompleteArgumentException", true, "IncompleteArgumentException", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "IncompleteArgumentException", true, "IncompleteArgumentException", "(String,String[])", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "LocaleUtils", true, "localeLookupList", "(Locale)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "LocaleUtils", true, "localeLookupList", "(Locale,Locale)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "LocaleUtils", true, "localeLookupList", "(Locale,Locale)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "NotImplementedException", true, "NotImplementedException", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "NotImplementedException", true, "NotImplementedException", "(String,Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "NotImplementedException", true, "NotImplementedException", "(String,Throwable)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "NotImplementedException", true, "NotImplementedException", "(Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "NullArgumentException", true, "NullArgumentException", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", true, "appendIdentityToString", "(StringBuffer,Object)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", true, "defaultIfNull", "(Object,Object)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", true, "defaultIfNull", "(Object,Object)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", true, "max", "(Comparable,Comparable)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", true, "max", "(Comparable,Comparable)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", true, "min", "(Comparable,Comparable)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", true, "min", "(Comparable,Comparable)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", true, "toString", "(Object,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "SerializationException", true, "SerializationException", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "SerializationException", true, "SerializationException", "(String,Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "SerializationException", true, "SerializationException", "(String,Throwable)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "SerializationException", true, "SerializationException", "(Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "SerializationUtils", true, "deserialize", "(InputStream)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "SerializationUtils", true, "deserialize", "(byte[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", true, "escapeSql", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", true, "unescapeCsv", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", true, "unescapeCsv", "(Writer,String)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", true, "unescapeHtml", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", true, "unescapeHtml", "(Writer,String)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", true, "unescapeXml", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", true, "unescapeXml", "(Writer,String)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "abbreviate", "(String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "abbreviate", "(String,int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "capitalise", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "capitaliseAllWords", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "capitalize", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "center", "(String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "center", "(String,int,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "center", "(String,int,String)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "center", "(String,int,char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "chomp", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "chomp", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "chompLast", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "chompLast", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "chop", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "chopNewline", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "clean", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "concatenate", "(Object[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "defaultIfEmpty", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "defaultIfEmpty", "(String,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "defaultString", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "defaultString", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "defaultString", "(String,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "deleteSpaces", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "deleteWhitespace", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "difference", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "difference", "(String,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "getChomp", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "getChomp", "(String,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "getCommonPrefix", "(String[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "getNestedString", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "getNestedString", "(String,String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "getPrechomp", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Collection,String)", "", "Argument[0].Element", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Collection,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Collection,char)", "", "Argument[0].Element", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Iterator,String)", "", "Argument[0].Element", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Iterator,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Iterator,char)", "", "Argument[0].Element", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Object[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Object[],String)", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Object[],String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Object[],String,int,int)", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Object[],String,int,int)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Object[],char)", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "join", "(Object[],char,int,int)", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "left", "(String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "leftPad", "(String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "leftPad", "(String,int,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "leftPad", "(String,int,String)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "leftPad", "(String,int,char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "lowerCase", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "mid", "(String,int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "overlay", "(String,String,int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "overlay", "(String,String,int,int)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "overlayString", "(String,String,int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "overlayString", "(String,String,int,int)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "prechomp", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "remove", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "remove", "(String,char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "removeEnd", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "removeEndIgnoreCase", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "removeStart", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "removeStartIgnoreCase", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "repeat", "(String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replace", "(String,String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replace", "(String,String,String)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replace", "(String,String,String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replace", "(String,String,String,int)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replaceChars", "(String,String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replaceChars", "(String,char,char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replaceEach", "(String,String[],String[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replaceEach", "(String,String[],String[])", "", "Argument[2].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replaceEachRepeatedly", "(String,String[],String[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replaceEachRepeatedly", "(String,String[],String[])", "", "Argument[2].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replaceOnce", "(String,String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "replaceOnce", "(String,String,String)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "reverse", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "reverseDelimited", "(String,char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "reverseDelimitedString", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "reverseDelimitedString", "(String,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "right", "(String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "rightPad", "(String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "rightPad", "(String,int,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "rightPad", "(String,int,String)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "rightPad", "(String,int,char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "split", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "split", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "split", "(String,String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "split", "(String,char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "splitByCharacterType", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "splitByCharacterTypeCamelCase", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "splitByWholeSeparator", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "splitByWholeSeparator", "(String,String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "splitByWholeSeparatorPreserveAllTokens", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "splitByWholeSeparatorPreserveAllTokens", "(String,String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "splitPreserveAllTokens", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "splitPreserveAllTokens", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "splitPreserveAllTokens", "(String,String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "splitPreserveAllTokens", "(String,char)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "strip", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "strip", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "stripAll", "(String[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "stripAll", "(String[],String)", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "stripEnd", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "stripStart", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "stripToEmpty", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "stripToNull", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "substring", "(String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "substring", "(String,int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "substringAfter", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "substringAfterLast", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "substringBefore", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "substringBeforeLast", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "substringBetween", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "substringBetween", "(String,String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "substringsBetween", "(String,String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "swapCase", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "trim", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "trimToEmpty", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "trimToNull", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "uncapitalise", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "uncapitalize", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", true, "upperCase", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "UnhandledException", true, "UnhandledException", "(String,Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "UnhandledException", true, "UnhandledException", "(String,Throwable)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "UnhandledException", true, "UnhandledException", "(Throwable)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "abbreviate", "(String,int,int,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "abbreviate", "(String,int,int,String)", "", "Argument[3]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "capitalize", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "capitalize", "(String,char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "capitalizeFully", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "capitalizeFully", "(String,char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "initials", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "initials", "(String,char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "swapCase", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "uncapitalize", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "uncapitalize", "(String,char[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "wrap", "(String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "wrap", "(String,int,String,boolean)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["org.apache.commons.lang", "WordUtils", true, "wrap", "(String,int,String,boolean)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"] + + + - addsTo: + pack: codeql/java-all + extensible: neutralModel + data: + - ["org.apache.commons.lang.builder", "CompareToBuilder", "reflectionCompare", "(Object,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", "reflectionCompare", "(Object,Object,Collection)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", "reflectionCompare", "(Object,Object,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", "reflectionCompare", "(Object,Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", "reflectionCompare", "(Object,Object,boolean,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", "reflectionCompare", "(Object,Object,boolean,Class,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "CompareToBuilder", "toComparison", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", "isEquals", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", "reflectionEquals", "(Object,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", "reflectionEquals", "(Object,Object,Collection)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", "reflectionEquals", "(Object,Object,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", "reflectionEquals", "(Object,Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", "reflectionEquals", "(Object,Object,boolean,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "EqualsBuilder", "reflectionEquals", "(Object,Object,boolean,Class,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", "HashCodeBuilder", "(int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", "reflectionHashCode", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", "reflectionHashCode", "(Object,Collection)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", "reflectionHashCode", "(Object,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", "reflectionHashCode", "(Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", "reflectionHashCode", "(int,int,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", "reflectionHashCode", "(int,int,Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", "reflectionHashCode", "(int,int,Object,boolean,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", "reflectionHashCode", "(int,int,Object,boolean,Class,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "HashCodeBuilder", "toHashCode", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "getUpToClass", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "isAppendStatics", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "isAppendTransients", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "setAppendStatics", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "setAppendTransients", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "setUpToClass", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "toString", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "toString", "(Object,ToStringStyle)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "toString", "(Object,ToStringStyle,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "toString", "(Object,ToStringStyle,boolean,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "toString", "(Object,ToStringStyle,boolean,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "toString", "(Object,ToStringStyle,boolean,boolean,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "toStringExclude", "(Object,Collection)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "toStringExclude", "(Object,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ReflectionToStringBuilder", "toStringExclude", "(Object,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", "getDefaultStyle", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", "reflectionToString", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", "reflectionToString", "(Object,ToStringStyle)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", "reflectionToString", "(Object,ToStringStyle,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", "reflectionToString", "(Object,ToStringStyle,boolean,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringBuilder", "setDefaultStyle", "(ToStringStyle)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "isArrayContentDetail", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "isDefaultFullDetail", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "isFieldSeparatorAtEnd", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "isFieldSeparatorAtStart", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "isShortClassName", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "isUseClassName", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "isUseFieldNames", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "isUseIdentityHashCode", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "isUseShortClassName", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "setArrayContentDetail", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "setDefaultFullDetail", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "setFieldSeparatorAtEnd", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "setFieldSeparatorAtStart", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "setShortClassName", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "setUseClassName", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "setUseFieldNames", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "setUseIdentityHashCode", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.builder", "ToStringStyle", "setUseShortClassName", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.enums", "Enum", "getEnumClass", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.enums", "EnumUtils", "getEnum", "(Class,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.enums", "EnumUtils", "getEnum", "(Class,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.enums", "EnumUtils", "getEnumList", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.enums", "EnumUtils", "getEnumMap", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.enums", "EnumUtils", "iterator", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.enums", "ValuedEnum", "getValue", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "addCauseMethodName", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "getFullStackTrace", "(Throwable)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "getStackFrames", "(Throwable)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "getStackTrace", "(Throwable)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "getThrowableCount", "(Throwable)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "indexOfThrowable", "(Throwable,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "indexOfThrowable", "(Throwable,Class,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "indexOfType", "(Throwable,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "indexOfType", "(Throwable,Class,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "isCauseMethodName", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "isNestedThrowable", "(Throwable)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "isThrowableNested", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "printRootCauseStackTrace", "(Throwable)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "printRootCauseStackTrace", "(Throwable,PrintStream)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "printRootCauseStackTrace", "(Throwable,PrintWriter)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "removeCauseMethodName", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "removeCommonFrames", "(List,List)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "ExceptionUtils", "setCause", "(Throwable,Throwable)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", "getMessages", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", "getThrowableCount", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", "indexOfThrowable", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", "indexOfThrowable", "(Class,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", "printPartialStackTrace", "(PrintWriter)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", "printStackTrace", "(PrintStream)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "Nestable", "printStackTrace", "(PrintWriter)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", "getThrowableCount", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", "indexOfThrowable", "(Class,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", "printStackTrace", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", "printStackTrace", "(PrintStream)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableDelegate", "printStackTrace", "(PrintWriter)", "summary", "df-generated"] + - ["org.apache.commons.lang.exception", "NestableError", "NestableError", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "DoubleRange", "DoubleRange", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "DoubleRange", "DoubleRange", "(Number,Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "DoubleRange", "DoubleRange", "(double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "DoubleRange", "DoubleRange", "(double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "FloatRange", "FloatRange", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "FloatRange", "FloatRange", "(Number,Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "FloatRange", "FloatRange", "(float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "FloatRange", "FloatRange", "(float,float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "add", "(Fraction)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "divideBy", "(Fraction)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "getDenominator", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "getFraction", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "getFraction", "(double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "getFraction", "(int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "getFraction", "(int,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "getNumerator", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "getProperNumerator", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "getProperWhole", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "getReducedFraction", "(int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "invert", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "multiplyBy", "(Fraction)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "negate", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "subtract", "(Fraction)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "toProperString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Fraction", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "max", "(double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "max", "(double,double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "max", "(double[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "max", "(float,float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "max", "(float,float,float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "max", "(float[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "min", "(double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "min", "(double,double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "min", "(double[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "min", "(float,float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "min", "(float,float,float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IEEE754rUtils", "min", "(float[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IntRange", "IntRange", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IntRange", "IntRange", "(Number,Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IntRange", "IntRange", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IntRange", "IntRange", "(int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "IntRange", "toArray", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "JVMRandom", "nextLong", "(long)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "LongRange", "LongRange", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "LongRange", "LongRange", "(Number,Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "LongRange", "LongRange", "(long)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "LongRange", "LongRange", "(long,long)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "LongRange", "toArray", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberRange", "NumberRange", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberRange", "NumberRange", "(Number,Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "compare", "(double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "compare", "(float,float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "createBigDecimal", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "createBigInteger", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "createDouble", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "createFloat", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "createInteger", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "createLong", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "createNumber", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "isDigits", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "isNumber", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(byte,byte,byte)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(byte[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(double,double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(double[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(float,float,float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(float[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(int,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(int[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(long,long,long)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(long[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(short,short,short)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "max", "(short[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(byte,byte,byte)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(byte[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(double,double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(double[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(float,float,float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(float[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(int,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(int[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(long,long,long)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(long[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(short,short,short)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "min", "(short[])", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "stringToInt", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "stringToInt", "(String,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "toDouble", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "toDouble", "(String,double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "toFloat", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "toFloat", "(String,float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "toInt", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "toInt", "(String,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "toLong", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "NumberUtils", "toLong", "(String,long)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextBoolean", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextBoolean", "(Random)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextDouble", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextDouble", "(Random)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextFloat", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextFloat", "(Random)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextInt", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextInt", "(Random)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextInt", "(Random,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextInt", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextLong", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "RandomUtils", "nextLong", "(Random)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "containsDouble", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "containsDouble", "(double)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "containsFloat", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "containsFloat", "(float)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "containsInteger", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "containsInteger", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "containsLong", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "containsLong", "(long)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "containsNumber", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "containsRange", "(Range)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "getMaximumDouble", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "getMaximumFloat", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "getMaximumInteger", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "getMaximumLong", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "getMaximumNumber", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "getMinimumDouble", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "getMinimumFloat", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "getMinimumInteger", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "getMinimumLong", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "getMinimumNumber", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "overlapsRange", "(Range)", "summary", "df-generated"] + - ["org.apache.commons.lang.math", "Range", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "Mutable", "getValue", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "Mutable", "setValue", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableBoolean", "MutableBoolean", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableBoolean", "MutableBoolean", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableBoolean", "booleanValue", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableBoolean", "setValue", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableBoolean", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "MutableByte", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "MutableByte", "(byte)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "add", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "add", "(byte)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "decrement", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "increment", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "setValue", "(byte)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "subtract", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "subtract", "(byte)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "toByte", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableByte", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "MutableDouble", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "MutableDouble", "(double)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "add", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "add", "(double)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "decrement", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "increment", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "isInfinite", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "isNaN", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "setValue", "(double)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "subtract", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "subtract", "(double)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "toDouble", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableDouble", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "MutableFloat", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "MutableFloat", "(float)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "add", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "add", "(float)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "decrement", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "increment", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "isInfinite", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "isNaN", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "setValue", "(float)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "subtract", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "subtract", "(float)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "toFloat", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableFloat", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "MutableInt", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "MutableInt", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "add", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "add", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "decrement", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "increment", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "setValue", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "subtract", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "subtract", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "toInteger", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableInt", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "MutableLong", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "MutableLong", "(long)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "add", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "add", "(long)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "decrement", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "increment", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "setValue", "(long)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "subtract", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "subtract", "(long)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "toLong", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableLong", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableObject", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "MutableShort", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "MutableShort", "(short)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "add", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "add", "(short)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "decrement", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "increment", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "setValue", "(short)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "subtract", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "subtract", "(short)", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "toShort", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.mutable", "MutableShort", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "ConstructorUtils", "getAccessibleConstructor", "(Class,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "ConstructorUtils", "getAccessibleConstructor", "(Class,Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "ConstructorUtils", "getMatchingAccessibleConstructor", "(Class,Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "ConstructorUtils", "invokeConstructor", "(Class,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "ConstructorUtils", "invokeConstructor", "(Class,Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "ConstructorUtils", "invokeConstructor", "(Class,Object[],Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "ConstructorUtils", "invokeExactConstructor", "(Class,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "ConstructorUtils", "invokeExactConstructor", "(Class,Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "ConstructorUtils", "invokeExactConstructor", "(Class,Object[],Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "getDeclaredField", "(Class,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "getDeclaredField", "(Class,String,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "getField", "(Class,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "getField", "(Class,String,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readDeclaredField", "(Object,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readDeclaredField", "(Object,String,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readDeclaredStaticField", "(Class,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readDeclaredStaticField", "(Class,String,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readField", "(Field,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readField", "(Field,Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readField", "(Object,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readField", "(Object,String,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readStaticField", "(Class,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readStaticField", "(Class,String,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readStaticField", "(Field)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "readStaticField", "(Field,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeDeclaredField", "(Object,String,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeDeclaredField", "(Object,String,Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeDeclaredStaticField", "(Class,String,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeDeclaredStaticField", "(Class,String,Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeField", "(Field,Object,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeField", "(Field,Object,Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeField", "(Object,String,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeField", "(Object,String,Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeStaticField", "(Class,String,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeStaticField", "(Class,String,Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeStaticField", "(Field,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "FieldUtils", "writeStaticField", "(Field,Object,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "clearCache", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "getAccessibleMethod", "(Class,String,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "getAccessibleMethod", "(Class,String,Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "getMatchingAccessibleMethod", "(Class,String,Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeExactMethod", "(Object,String,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeExactMethod", "(Object,String,Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeExactMethod", "(Object,String,Object[],Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeExactStaticMethod", "(Class,String,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeExactStaticMethod", "(Class,String,Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeExactStaticMethod", "(Class,String,Object[],Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeMethod", "(Object,String,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeMethod", "(Object,String,Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeMethod", "(Object,String,Object[],Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeStaticMethod", "(Class,String,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeStaticMethod", "(Class,String,Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "invokeStaticMethod", "(Class,String,Object[],Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang.reflect", "MethodUtils", "setCacheMethods", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "CompositeFormat", "reformat", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "StrBuilder", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "appendln", "(StrBuilder)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "appendln", "(StrBuilder,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "appendln", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "appendln", "(String,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "appendln", "(StringBuffer)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "appendln", "(StringBuffer,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "appendln", "(char[])", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "appendln", "(char[],int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "asReader", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "asTokenizer", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "asWriter", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "capacity", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "charAt", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "contains", "(StrMatcher)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "contains", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "contains", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "endsWith", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "equals", "(StrBuilder)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "equalsIgnoreCase", "(StrBuilder)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "indexOf", "(StrMatcher)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "indexOf", "(StrMatcher,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "indexOf", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "indexOf", "(String,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "indexOf", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "indexOf", "(char,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "isEmpty", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "lastIndexOf", "(StrMatcher)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "lastIndexOf", "(StrMatcher,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "lastIndexOf", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "lastIndexOf", "(String,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "lastIndexOf", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "lastIndexOf", "(char,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "length", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "size", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrBuilder", "startsWith", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrLookup", "lookup", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrLookup", "noneLookup", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrLookup", "systemPropertiesLookup", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "charMatcher", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "commaMatcher", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "doubleQuoteMatcher", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "isMatch", "(char[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "isMatch", "(char[],int,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "noneMatcher", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "quoteMatcher", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "singleQuoteMatcher", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "spaceMatcher", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "splitMatcher", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "tabMatcher", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrMatcher", "trimMatcher", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", "getEscapeChar", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", "replace", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", "replace", "(Object,Map)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", "replace", "(Object,Map,String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", "replaceIn", "(StrBuilder)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", "replaceIn", "(StrBuilder,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", "replaceIn", "(StringBuffer)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", "replaceIn", "(StringBuffer,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", "replaceSystemProperties", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrSubstitutor", "setEscapeChar", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", "getCSVInstance", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", "getTSVInstance", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", "isEmptyTokenAsNull", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", "isIgnoreEmptyTokens", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.text", "StrTokenizer", "size", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(Calendar,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(Calendar,String,Locale)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(Calendar,String,TimeZone)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(Calendar,String,TimeZone,Locale)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(Date,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(Date,String,Locale)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(Date,String,TimeZone)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(Date,String,TimeZone,Locale)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(long,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(long,String,Locale)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(long,String,TimeZone)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "format", "(long,String,TimeZone,Locale)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "formatUTC", "(Date,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "formatUTC", "(Date,String,Locale)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "formatUTC", "(long,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateFormatUtils", "formatUTC", "(long,String,Locale)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "add", "(Date,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "addDays", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "addHours", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "addMilliseconds", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "addMinutes", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "addMonths", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "addSeconds", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "addWeeks", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "addYears", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "getFragmentInDays", "(Calendar,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "getFragmentInDays", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "getFragmentInHours", "(Calendar,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "getFragmentInHours", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "getFragmentInMilliseconds", "(Calendar,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "getFragmentInMilliseconds", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "getFragmentInMinutes", "(Calendar,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "getFragmentInMinutes", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "getFragmentInSeconds", "(Calendar,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "getFragmentInSeconds", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "isSameDay", "(Calendar,Calendar)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "isSameDay", "(Date,Date)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "isSameInstant", "(Calendar,Calendar)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "isSameInstant", "(Date,Date)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "isSameLocalTime", "(Calendar,Calendar)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "iterator", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "parseDate", "(String,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "round", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "round", "(Object,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "setDays", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "setHours", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "setMilliseconds", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "setMinutes", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "setMonths", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "setSeconds", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "setYears", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "truncate", "(Date,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DateUtils", "truncate", "(Object,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DurationFormatUtils", "formatDuration", "(long,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DurationFormatUtils", "formatDuration", "(long,String,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DurationFormatUtils", "formatDurationHMS", "(long)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DurationFormatUtils", "formatDurationISO", "(long)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DurationFormatUtils", "formatDurationWords", "(long,boolean,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DurationFormatUtils", "formatPeriod", "(long,long,String)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DurationFormatUtils", "formatPeriod", "(long,long,String,boolean,TimeZone)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "DurationFormatUtils", "formatPeriodISO", "(long,long)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", "format", "(Calendar)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", "format", "(Date)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", "format", "(long)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", "getDateInstance", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", "getDateTimeInstance", "(int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", "getInstance", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", "getMaxLengthEstimate", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", "getTimeInstance", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "FastDateFormat", "getTimeZoneOverridesCalendar", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "getSplitTime", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "getStartTime", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "getTime", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "reset", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "resume", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "split", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "start", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "stop", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "suspend", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "toSplitString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang.time", "StopWatch", "unsplit", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(boolean[],boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(boolean[],int,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(double[],double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(double[],int,double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(float[],float)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(float[],int,float)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(int[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(int[],int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(long[],int,long)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(long[],long)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(short[],int,short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "add", "(short[],short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "addAll", "(boolean[],boolean[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "addAll", "(double[],double[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "addAll", "(float[],float[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "addAll", "(int[],int[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "addAll", "(long[],long[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "addAll", "(short[],short[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "clone", "(boolean[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "clone", "(double[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "clone", "(float[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "clone", "(int[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "clone", "(long[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "clone", "(short[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "contains", "(Object[],Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "contains", "(boolean[],boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "contains", "(byte[],byte)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "contains", "(char[],char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "contains", "(double[],double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "contains", "(double[],double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "contains", "(float[],float)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "contains", "(int[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "contains", "(long[],long)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "contains", "(short[],short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "getLength", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "hashCode", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(Object[],Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(Object[],Object,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(boolean[],boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(boolean[],boolean,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(byte[],byte)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(byte[],byte,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(char[],char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(char[],char,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(double[],double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(double[],double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(double[],double,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(double[],double,int,double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(float[],float)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(float[],float,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(int[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(int[],int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(long[],long)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(long[],long,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(short[],short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "indexOf", "(short[],short,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isEmpty", "(Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isEmpty", "(boolean[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isEmpty", "(byte[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isEmpty", "(char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isEmpty", "(double[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isEmpty", "(float[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isEmpty", "(int[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isEmpty", "(long[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isEmpty", "(short[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isEquals", "(Object,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isSameLength", "(Object[],Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isSameLength", "(boolean[],boolean[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isSameLength", "(byte[],byte[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isSameLength", "(char[],char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isSameLength", "(double[],double[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isSameLength", "(float[],float[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isSameLength", "(int[],int[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isSameLength", "(long[],long[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isSameLength", "(short[],short[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "isSameType", "(Object,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(Object[],Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(Object[],Object,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(boolean[],boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(boolean[],boolean,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(byte[],byte)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(byte[],byte,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(char[],char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(char[],char,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(double[],double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(double[],double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(double[],double,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(double[],double,int,double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(float[],float)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(float[],float,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(int[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(int[],int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(long[],long)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(long[],long,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(short[],short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "lastIndexOf", "(short[],short,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "remove", "(boolean[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "remove", "(double[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "remove", "(float[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "remove", "(int[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "remove", "(long[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "remove", "(short[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "removeElement", "(boolean[],boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "removeElement", "(double[],double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "removeElement", "(float[],float)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "removeElement", "(int[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "removeElement", "(long[],long)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "removeElement", "(short[],short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "reverse", "(Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "reverse", "(boolean[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "reverse", "(byte[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "reverse", "(char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "reverse", "(double[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "reverse", "(float[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "reverse", "(int[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "reverse", "(long[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "reverse", "(short[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "subarray", "(boolean[],int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "subarray", "(double[],int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "subarray", "(float[],int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "subarray", "(int[],int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "subarray", "(long[],int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "subarray", "(short[],int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toObject", "(boolean[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toObject", "(byte[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toObject", "(char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toObject", "(double[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toObject", "(float[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toObject", "(int[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toObject", "(long[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toObject", "(short[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Boolean[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Boolean[],boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Byte[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Byte[],byte)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Character[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Character[],char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Double[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Double[],double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Float[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Float[],float)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Integer[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Integer[],int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Long[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Long[],long)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Short[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ArrayUtils", "toPrimitive", "(Short[],short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "BitField", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "clear", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "clearByte", "(byte)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "clearShort", "(short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "getRawValue", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "getShortRawValue", "(short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "getShortValue", "(short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "getValue", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "isAllSet", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "isSet", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "set", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "setBoolean", "(int,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "setByte", "(byte)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "setByteBoolean", "(byte,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "setShort", "(short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "setShortBoolean", "(short,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "setShortValue", "(short,short)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BitField", "setValue", "(int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "isFalse", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "isNotFalse", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "isNotTrue", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "isTrue", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "negate", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBoolean", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBoolean", "(Integer,Integer,Integer)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBoolean", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBoolean", "(String,String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBoolean", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBoolean", "(int,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBooleanDefaultIfNull", "(Boolean,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBooleanObject", "(Integer)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBooleanObject", "(Integer,Integer,Integer,Integer)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBooleanObject", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBooleanObject", "(String,String,String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBooleanObject", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBooleanObject", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toBooleanObject", "(int,int,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toInteger", "(Boolean,int,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toInteger", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toInteger", "(boolean,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toIntegerObject", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toIntegerObject", "(Boolean,Integer,Integer,Integer)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toIntegerObject", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toIntegerObject", "(boolean,Integer,Integer)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toStringOnOff", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toStringOnOff", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toStringTrueFalse", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toStringTrueFalse", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toStringYesNo", "(Boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "toStringYesNo", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "xor", "(Boolean[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "BooleanUtils", "xor", "(boolean[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharEncoding", "isSupported", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharRange", "CharRange", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharRange", "CharRange", "(char,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharRange", "CharRange", "(char,char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharRange", "CharRange", "(char,char,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharRange", "contains", "(CharRange)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharRange", "contains", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharRange", "getEnd", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharRange", "getStart", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharRange", "isNegated", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharSet", "contains", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharSet", "getInstance", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharSet", "getInstance", "(String[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharSet", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharSetUtils", "count", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharSetUtils", "count", "(String,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharSetUtils", "evaluateSet", "(String[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharSetUtils", "keep", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharSetUtils", "keep", "(String,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "isAscii", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "isAsciiAlpha", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "isAsciiAlphaLower", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "isAsciiAlphaUpper", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "isAsciiAlphanumeric", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "isAsciiControl", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "isAsciiNumeric", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "isAsciiPrintable", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toChar", "(Character)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toChar", "(Character,char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toChar", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toChar", "(String,char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toCharacterObject", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toCharacterObject", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toIntValue", "(Character)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toIntValue", "(Character,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toIntValue", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toIntValue", "(char,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toString", "(Character)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "toString", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "unicodeEscaped", "(Character)", "summary", "df-generated"] + - ["org.apache.commons.lang", "CharUtils", "unicodeEscaped", "(char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "convertClassNamesToClasses", "(List)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "convertClassesToClassNames", "(List)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getAllInterfaces", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getAllSuperclasses", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getClass", "(ClassLoader,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getClass", "(ClassLoader,String,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getClass", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getClass", "(String,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getPackageCanonicalName", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getPackageName", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getPublicMethod", "(Class,String,Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getShortCanonicalName", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "getShortClassName", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "isAssignable", "(Class,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "isAssignable", "(Class,Class,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "isAssignable", "(Class[],Class[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "isAssignable", "(Class[],Class[],boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "isInnerClass", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "primitiveToWrapper", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "toClass", "(Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "ClassUtils", "wrapperToPrimitive", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "IllegalClassException", "IllegalClassException", "(Class,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "IllegalClassException", "IllegalClassException", "(Class,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "LocaleUtils", "availableLocaleList", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "LocaleUtils", "availableLocaleSet", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "LocaleUtils", "countriesByLanguage", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "LocaleUtils", "isAvailableLocale", "(Locale)", "summary", "df-generated"] + - ["org.apache.commons.lang", "LocaleUtils", "languagesByCountry", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "LocaleUtils", "toLocale", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NotImplementedException", "NotImplementedException", "(Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberRange", "NumberRange", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberRange", "NumberRange", "(Number,Number)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberRange", "getMaximum", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberRange", "getMinimum", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberRange", "includesNumber", "(Number)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberRange", "includesRange", "(NumberRange)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberRange", "overlaps", "(NumberRange)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberRange", "toString", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "compare", "(double,double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "compare", "(float,float)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "createBigDecimal", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "createBigInteger", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "createDouble", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "createFloat", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "createInteger", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "createLong", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "createNumber", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "isDigits", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "isNumber", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "maximum", "(int,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "maximum", "(long,long,long)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "minimum", "(int,int,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "minimum", "(long,long,long)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "stringToInt", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "NumberUtils", "stringToInt", "(String,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", "equals", "(Object,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", "hashCode", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", "identityToString", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", "identityToString", "(StringBuffer,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "ObjectUtils", "toString", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "random", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "random", "(int,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "random", "(int,boolean,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "random", "(int,char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "random", "(int,int,int,boolean,boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "random", "(int,int,int,boolean,boolean,char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "random", "(int,int,int,boolean,boolean,char[],Random)", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "randomAlphabetic", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "randomAlphanumeric", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "randomAscii", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "RandomStringUtils", "randomNumeric", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "SerializationUtils", "clone", "(Serializable)", "summary", "df-generated"] + - ["org.apache.commons.lang", "SerializationUtils", "serialize", "(Serializable)", "summary", "df-generated"] + - ["org.apache.commons.lang", "SerializationUtils", "serialize", "(Serializable,OutputStream)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "escapeCsv", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "escapeCsv", "(Writer,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "escapeHtml", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "escapeHtml", "(Writer,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "escapeJava", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "escapeJava", "(Writer,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "escapeJavaScript", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "escapeJavaScript", "(Writer,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "escapeXml", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "escapeXml", "(Writer,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "unescapeJava", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "unescapeJava", "(Writer,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "unescapeJavaScript", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringEscapeUtils", "unescapeJavaScript", "(Writer,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "contains", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "contains", "(String,char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "containsAny", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "containsAny", "(String,char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "containsIgnoreCase", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "containsNone", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "containsNone", "(String,char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "containsOnly", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "containsOnly", "(String,char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "countMatches", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "endsWith", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "endsWithIgnoreCase", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "equals", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "equalsIgnoreCase", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "escape", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "getLevenshteinDistance", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOf", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOf", "(String,String,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOf", "(String,char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOf", "(String,char,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOfAny", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOfAny", "(String,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOfAny", "(String,char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOfAnyBut", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOfAnyBut", "(String,char[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOfDifference", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "indexOfDifference", "(String[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isAlpha", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isAlphaSpace", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isAlphanumeric", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isAlphanumericSpace", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isAsciiPrintable", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isBlank", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isEmpty", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isNotBlank", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isNotEmpty", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isNumeric", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isNumericSpace", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "isWhitespace", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "lastIndexOf", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "lastIndexOf", "(String,String,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "lastIndexOf", "(String,char)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "lastIndexOf", "(String,char,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "lastIndexOfAny", "(String,String[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "length", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "ordinalIndexOf", "(String,String,int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "startsWith", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "StringUtils", "startsWithIgnoreCase", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "SystemUtils", "getJavaHome", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "SystemUtils", "getJavaIoTmpDir", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "SystemUtils", "getJavaVersion", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "SystemUtils", "getUserDir", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "SystemUtils", "getUserHome", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "SystemUtils", "isJavaAwtHeadless", "()", "summary", "df-generated"] + - ["org.apache.commons.lang", "SystemUtils", "isJavaVersionAtLeast", "(float)", "summary", "df-generated"] + - ["org.apache.commons.lang", "SystemUtils", "isJavaVersionAtLeast", "(int)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "allElementsOfType", "(Collection,Class)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "allElementsOfType", "(Collection,Class,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "isTrue", "(boolean)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "isTrue", "(boolean,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "isTrue", "(boolean,String,Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "isTrue", "(boolean,String,double)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "isTrue", "(boolean,String,long)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "noNullElements", "(Collection)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "noNullElements", "(Collection,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "noNullElements", "(Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "noNullElements", "(Object[],String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "notEmpty", "(Collection)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "notEmpty", "(Collection,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "notEmpty", "(Map)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "notEmpty", "(Map,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "notEmpty", "(Object[])", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "notEmpty", "(Object[],String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "notEmpty", "(String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "notEmpty", "(String,String)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "notNull", "(Object)", "summary", "df-generated"] + - ["org.apache.commons.lang", "Validate", "notNull", "(Object,String)", "summary", "df-generated"] diff --git a/java/ql/src/change-notes/2023-06-23-apache-commons-lang.md b/java/ql/src/change-notes/2023-06-23-apache-commons-lang.md new file mode 100644 index 00000000000..dc33878d2e5 --- /dev/null +++ b/java/ql/src/change-notes/2023-06-23-apache-commons-lang.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* New models have been added for `org.apache.commons.lang`. From fba753ce61c95513b5d3f537671d1b46902e5786 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 24 Jun 2023 18:59:25 +0100 Subject: [PATCH 305/364] C++: Add more test cases to 'cpp/invalid-pointer-deref'. --- .../InvalidPointerDeref.expected | 63 +++++++++ .../CWE/CWE-193/pointer-deref/test.cpp | 121 ++++++++++++++++++ 2 files changed, 184 insertions(+) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected index 7c27659de1f..121edbaa801 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected @@ -788,6 +788,29 @@ edges | test.cpp:427:14:427:27 | new[] | test.cpp:433:5:433:6 | xs | | test.cpp:433:5:433:6 | xs | test.cpp:433:5:433:17 | access to array | | test.cpp:433:5:433:17 | access to array | test.cpp:433:5:433:21 | Store: ... = ... | +| test.cpp:439:14:439:27 | new[] | test.cpp:444:5:444:6 | xs | +| test.cpp:444:5:444:6 | xs | test.cpp:444:5:444:15 | access to array | +| test.cpp:444:5:444:15 | access to array | test.cpp:444:5:444:19 | Store: ... = ... | +| test.cpp:450:14:450:27 | new[] | test.cpp:455:5:455:6 | xs | +| test.cpp:455:5:455:6 | xs | test.cpp:455:5:455:15 | access to array | +| test.cpp:455:5:455:15 | access to array | test.cpp:455:5:455:19 | Store: ... = ... | +| test.cpp:461:14:461:27 | new[] | test.cpp:466:5:466:6 | xs | +| test.cpp:466:5:466:6 | xs | test.cpp:466:5:466:15 | access to array | +| test.cpp:466:5:466:15 | access to array | test.cpp:466:5:466:19 | Store: ... = ... | +| test.cpp:472:14:472:27 | new[] | test.cpp:477:5:477:6 | xs | +| test.cpp:477:5:477:6 | xs | test.cpp:477:5:477:15 | access to array | +| test.cpp:477:5:477:15 | access to array | test.cpp:477:5:477:19 | Store: ... = ... | +| test.cpp:483:14:483:27 | new[] | test.cpp:488:5:488:6 | xs | +| test.cpp:488:5:488:6 | xs | test.cpp:488:5:488:15 | access to array | +| test.cpp:488:5:488:15 | access to array | test.cpp:488:5:488:19 | Store: ... = ... | +| test.cpp:494:14:494:31 | new[] | test.cpp:499:5:499:6 | xs | +| test.cpp:505:14:505:31 | new[] | test.cpp:510:5:510:6 | xs | +| test.cpp:516:14:516:31 | new[] | test.cpp:521:5:521:6 | xs | +| test.cpp:527:14:527:31 | new[] | test.cpp:532:5:532:6 | xs | +| test.cpp:538:14:538:31 | new[] | test.cpp:543:5:543:6 | xs | +| test.cpp:549:14:549:31 | new[] | test.cpp:554:5:554:6 | xs | +| test.cpp:554:5:554:6 | xs | test.cpp:554:5:554:15 | access to array | +| test.cpp:554:5:554:15 | access to array | test.cpp:554:5:554:19 | Store: ... = ... | nodes | test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc | | test.cpp:5:15:5:15 | p | semmle.label | p | @@ -1157,6 +1180,40 @@ nodes | test.cpp:433:5:433:6 | xs | semmle.label | xs | | test.cpp:433:5:433:17 | access to array | semmle.label | access to array | | test.cpp:433:5:433:21 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:439:14:439:27 | new[] | semmle.label | new[] | +| test.cpp:444:5:444:6 | xs | semmle.label | xs | +| test.cpp:444:5:444:15 | access to array | semmle.label | access to array | +| test.cpp:444:5:444:19 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:450:14:450:27 | new[] | semmle.label | new[] | +| test.cpp:455:5:455:6 | xs | semmle.label | xs | +| test.cpp:455:5:455:15 | access to array | semmle.label | access to array | +| test.cpp:455:5:455:19 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:461:14:461:27 | new[] | semmle.label | new[] | +| test.cpp:466:5:466:6 | xs | semmle.label | xs | +| test.cpp:466:5:466:15 | access to array | semmle.label | access to array | +| test.cpp:466:5:466:19 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:472:14:472:27 | new[] | semmle.label | new[] | +| test.cpp:477:5:477:6 | xs | semmle.label | xs | +| test.cpp:477:5:477:15 | access to array | semmle.label | access to array | +| test.cpp:477:5:477:19 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:483:14:483:27 | new[] | semmle.label | new[] | +| test.cpp:488:5:488:6 | xs | semmle.label | xs | +| test.cpp:488:5:488:15 | access to array | semmle.label | access to array | +| test.cpp:488:5:488:19 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:494:14:494:31 | new[] | semmle.label | new[] | +| test.cpp:499:5:499:6 | xs | semmle.label | xs | +| test.cpp:505:14:505:31 | new[] | semmle.label | new[] | +| test.cpp:510:5:510:6 | xs | semmle.label | xs | +| test.cpp:516:14:516:31 | new[] | semmle.label | new[] | +| test.cpp:521:5:521:6 | xs | semmle.label | xs | +| test.cpp:527:14:527:31 | new[] | semmle.label | new[] | +| test.cpp:532:5:532:6 | xs | semmle.label | xs | +| test.cpp:538:14:538:31 | new[] | semmle.label | new[] | +| test.cpp:543:5:543:6 | xs | semmle.label | xs | +| test.cpp:549:14:549:31 | new[] | semmle.label | new[] | +| test.cpp:554:5:554:6 | xs | semmle.label | xs | +| test.cpp:554:5:554:15 | access to array | semmle.label | access to array | +| test.cpp:554:5:554:19 | Store: ... = ... | semmle.label | Store: ... = ... | subpaths #select | test.cpp:6:14:6:15 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size | @@ -1187,3 +1244,9 @@ subpaths | test.cpp:407:3:407:22 | Store: ... = ... | test.cpp:404:12:404:25 | new[] | test.cpp:407:3:407:22 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:404:12:404:25 | new[] | new[] | test.cpp:407:10:407:17 | ... - ... | ... - ... | | test.cpp:419:7:419:15 | Store: ... = ... | test.cpp:417:16:417:33 | new[] | test.cpp:419:7:419:15 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:417:16:417:33 | new[] | new[] | test.cpp:419:10:419:10 | i | i | | test.cpp:433:5:433:21 | Store: ... = ... | test.cpp:427:14:427:27 | new[] | test.cpp:433:5:433:21 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:427:14:427:27 | new[] | new[] | test.cpp:433:8:433:16 | ... ++ | ... ++ | +| test.cpp:444:5:444:19 | Store: ... = ... | test.cpp:439:14:439:27 | new[] | test.cpp:444:5:444:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:439:14:439:27 | new[] | new[] | test.cpp:444:8:444:14 | src_pos | src_pos | +| test.cpp:455:5:455:19 | Store: ... = ... | test.cpp:450:14:450:27 | new[] | test.cpp:455:5:455:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:450:14:450:27 | new[] | new[] | test.cpp:455:8:455:14 | src_pos | src_pos | +| test.cpp:466:5:466:19 | Store: ... = ... | test.cpp:461:14:461:27 | new[] | test.cpp:466:5:466:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:461:14:461:27 | new[] | new[] | test.cpp:466:8:466:14 | src_pos | src_pos | +| test.cpp:477:5:477:19 | Store: ... = ... | test.cpp:472:14:472:27 | new[] | test.cpp:477:5:477:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:472:14:472:27 | new[] | new[] | test.cpp:477:8:477:14 | src_pos | src_pos | +| test.cpp:488:5:488:19 | Store: ... = ... | test.cpp:483:14:483:27 | new[] | test.cpp:488:5:488:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:483:14:483:27 | new[] | new[] | test.cpp:488:8:488:14 | src_pos | src_pos | +| test.cpp:554:5:554:19 | Store: ... = ... | test.cpp:549:14:549:31 | new[] | test.cpp:554:5:554:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:549:14:549:31 | new[] | new[] | test.cpp:554:8:554:14 | src_pos | src_pos | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp index 4048c15be8b..3fd047fa180 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp @@ -433,3 +433,124 @@ void test31(unsigned size, unsigned src_pos) xs[dst_pos++] = 0; // GOOD [FALSE POSITIVE] } } + +void test31_simple1(unsigned size, unsigned src_pos) +{ + char *xs = new char[size]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos < size) { + xs[src_pos] = 0; // GOOD [FALSE POSITIVE] + } +} + +void test31_simple2(unsigned size, unsigned src_pos) +{ + char *xs = new char[size]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos < size + 1) { + xs[src_pos] = 0; // BAD + } +} + +void test31_simple3(unsigned size, unsigned src_pos) +{ + char *xs = new char[size]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos - 1 < size) { + xs[src_pos] = 0; // BAD + } +} + +void test31_simple4(unsigned size, unsigned src_pos) +{ + char *xs = new char[size]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos < size - 1) { + xs[src_pos] = 0; // GOOD [FALSE POSITIVE] + } +} + +void test31_simple5(unsigned size, unsigned src_pos) +{ + char *xs = new char[size]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos + 1 < size) { + xs[src_pos] = 0; // GOOD [FALSE POSITIVE] + } +} + +void test31_simple1_plus1(unsigned size, unsigned src_pos) +{ + char *xs = new char[size + 1]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos < size) { + xs[src_pos] = 0; // GOOD + } +} + +void test31_simple2_plus1(unsigned size, unsigned src_pos) +{ + char *xs = new char[size + 1]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos < size + 1) { + xs[src_pos] = 0; // GOOD + } +} + +void test31_simple3_plus1(unsigned size, unsigned src_pos) +{ + char *xs = new char[size + 1]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos - 1 < size) { + xs[src_pos] = 0; // GOOD + } +} + +void test31_simple4_plus1(unsigned size, unsigned src_pos) +{ + char *xs = new char[size + 1]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos < size - 1) { + xs[src_pos] = 0; // GOOD + } +} + +void test31_simple5_plus1(unsigned size, unsigned src_pos) +{ + char *xs = new char[size + 1]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos + 1 < size) { + xs[src_pos] = 0; // GOOD + } +} + +void test31_simple1_sub1(unsigned size, unsigned src_pos) +{ + char *xs = new char[size - 1]; + if (src_pos > size) { + src_pos = size; + } + if(src_pos < size) { + xs[src_pos] = 0; // BAD + } +} From 9d5b8cff2eee94e7afc79e3dd6a31911841b94ac Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 24 Jun 2023 19:00:08 +0100 Subject: [PATCH 306/364] C++: Add a barrier to the 'cpp/invalid-pointer-deref' query. --- .../CWE/CWE-193/InvalidPointerDeref.ql | 111 ++++++++++++++++-- 1 file changed, 100 insertions(+), 11 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql index 478ab2cc92a..a202f3ed380 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -19,6 +19,8 @@ import cpp import semmle.code.cpp.ir.dataflow.internal.ProductFlow import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific +import semmle.code.cpp.ir.ValueNumbering +import semmle.code.cpp.controlflow.IRGuards import semmle.code.cpp.ir.IR import codeql.util.Unit @@ -67,6 +69,84 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) { ) } +/** + * A module that encapsulates a barrier guard to remove false positives from flow like: + * ```cpp + * char *p = new char[size]; + * // ... + * unsigned n = size; + * // ... + * if(n < size) { + * use(*p[n]); + * } + * ``` + * In this case, the sink pair identified by the product flow library (without any additional barriers) + * would be `(p, n)` (where `n` is the `n` in `p[n]`), because there exists a pointer-arithmetic + * instruction `pai` such that: + * 1. The left-hand of `pai` flows from the allocation, and + * 2. The right-hand of `pai` is non-strictly upper bounded by `n` (where `n` is the `n` in `p[n]`) + * but because there's a strict comparison that compares `n` against the size of the allocation this + * snippet is fine. + */ +module Barrier2 { + private class FlowState2 = AllocToInvalidPointerConfig::FlowState2; + + private module BarrierConfig2 implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + // The sources is the same as in the sources for the second + // projection in the `AllocToInvalidPointerConfig` module. + hasSize(_, source, _) + } + + additional predicate isSink( + DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, FlowState2 state, + boolean testIsTrue + ) { + // The sink is any "large" side of a relational comparison. + g.comparesLt(left.asOperand(), right.asOperand(), state, true, testIsTrue) + } + + predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) } + } + + private import DataFlow::Global + + private FlowState2 getAFlowStateForNode(DataFlow::Node node) { + exists(DataFlow::Node source | + flow(source, node) and + hasSize(_, source, result) + ) + } + + private predicate operandGuardChecks( + IRGuardCondition g, Operand left, Operand right, FlowState2 state, boolean edge + ) { + exists(DataFlow::Node nLeft, DataFlow::Node nRight, FlowState2 state0 | + nRight.asOperand() = right and + nLeft.asOperand() = left and + BarrierConfig2::isSink(nLeft, nRight, g, state0, edge) and + state = getAFlowStateForNode(nRight) and + state0 <= state + ) + } + + Instruction getABarrierInstruction(FlowState2 state) { + exists(IRGuardCondition g, Operand right, ValueNumber value, boolean edge | + operandGuardChecks(g, value.getAUse(), right, state, edge) and + result = value.getAnInstruction() and + g.controls(result.getBlock(), edge) + ) + } + + DataFlow::Node getABarrierNode(FlowState2 state) { + result.asOperand() = getABarrierInstruction(state).getAUse() + } + + IRBlock getABarrierBlock(FlowState2 state) { + result.getAnInstruction() = getABarrierInstruction(state) + } +} + /** * A product-flow configuration for flow from an (allocation, size) pair to a * pointer-arithmetic operation that is non-strictly upper-bounded by `allocation + size`. @@ -111,15 +191,14 @@ module AllocToInvalidPointerConfig implements ProductFlow::StateConfigSig { exists(state1) and // We check that the delta computed by the range analysis matches the // state value that we set in `isSourcePair`. - exists(int delta | - isSinkImpl(_, sink1, sink2, delta) and - state2 = delta - ) + isSinkImpl(_, sink1, sink2, state2) } predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() } - predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() } + predicate isBarrier2(DataFlow::Node node, FlowState2 state) { + node = Barrier2::getABarrierNode(state) + } predicate isBarrierIn1(DataFlow::Node node) { isSourcePair(node, _, _, _) } @@ -163,7 +242,8 @@ predicate pointerAddInstructionHasBounds( exists(Instruction right | pai.getRight() = right and pai.getLeft() = sink1.asInstruction() and - bounded1(right, sink2.asInstruction(), delta) + bounded1(right, sink2.asInstruction(), delta) and + not [right, sink2.asInstruction()] = Barrier2::getABarrierInstruction(delta) ) } @@ -246,12 +326,21 @@ module InvalidPointerToDerefFlow = DataFlow::Global predicate invalidPointerToDerefSource( PointerArithmeticInstruction pai, DataFlow::Node source, int delta ) { - exists(AllocToInvalidPointerFlow::PathNode1 p, DataFlow::Node sink1 | - pragma[only_bind_out](p.getNode()) = sink1 and - AllocToInvalidPointerFlow::flowPath(_, _, pragma[only_bind_into](p), _) and - isSinkImpl(pai, sink1, _, _) and + exists( + AllocToInvalidPointerFlow::PathNode1 p1, AllocToInvalidPointerFlow::PathNode2 p2, + DataFlow::Node sink1, DataFlow::Node sink2, int delta0 + | + pragma[only_bind_out](p1.getNode()) = sink1 and + pragma[only_bind_out](p2.getNode()) = sink2 and + AllocToInvalidPointerFlow::flowPath(_, _, pragma[only_bind_into](p1), pragma[only_bind_into](p2)) and + // Note that `delta` is not necessarily equal to `delta0`: + // `delta0` is the constant offset added to the size of the allocation, and + // delta is the constant difference between the pointer-arithmetic instruction + // and the instruction computing the address for which we will search for a dereference. + isSinkImpl(pai, sink1, sink2, delta0) and bounded2(source.asInstruction(), pai, delta) and - delta >= 0 + delta >= 0 and + not source.getBasicBlock() = Barrier2::getABarrierBlock(delta0) ) } From c1077fe75d4819fe6a3f64c811d155344cf5a334 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 24 Jun 2023 19:01:23 +0100 Subject: [PATCH 307/364] C++: Accept test changes. --- .../InvalidPointerDeref.expected | 25 ------------------- .../CWE/CWE-193/pointer-deref/test.cpp | 10 ++++---- 2 files changed, 5 insertions(+), 30 deletions(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected index 121edbaa801..8d0233216b6 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected @@ -783,14 +783,8 @@ edges | test.cpp:407:7:407:8 | xs | test.cpp:407:3:407:18 | access to array | | test.cpp:407:7:407:8 | xs indirection | test.cpp:407:7:407:8 | xs | | test.cpp:417:16:417:33 | new[] | test.cpp:419:7:419:8 | xs | -| test.cpp:419:7:419:8 | xs | test.cpp:419:7:419:11 | access to array | -| test.cpp:419:7:419:11 | access to array | test.cpp:419:7:419:15 | Store: ... = ... | | test.cpp:427:14:427:27 | new[] | test.cpp:433:5:433:6 | xs | -| test.cpp:433:5:433:6 | xs | test.cpp:433:5:433:17 | access to array | -| test.cpp:433:5:433:17 | access to array | test.cpp:433:5:433:21 | Store: ... = ... | | test.cpp:439:14:439:27 | new[] | test.cpp:444:5:444:6 | xs | -| test.cpp:444:5:444:6 | xs | test.cpp:444:5:444:15 | access to array | -| test.cpp:444:5:444:15 | access to array | test.cpp:444:5:444:19 | Store: ... = ... | | test.cpp:450:14:450:27 | new[] | test.cpp:455:5:455:6 | xs | | test.cpp:455:5:455:6 | xs | test.cpp:455:5:455:15 | access to array | | test.cpp:455:5:455:15 | access to array | test.cpp:455:5:455:19 | Store: ... = ... | @@ -798,11 +792,7 @@ edges | test.cpp:466:5:466:6 | xs | test.cpp:466:5:466:15 | access to array | | test.cpp:466:5:466:15 | access to array | test.cpp:466:5:466:19 | Store: ... = ... | | test.cpp:472:14:472:27 | new[] | test.cpp:477:5:477:6 | xs | -| test.cpp:477:5:477:6 | xs | test.cpp:477:5:477:15 | access to array | -| test.cpp:477:5:477:15 | access to array | test.cpp:477:5:477:19 | Store: ... = ... | | test.cpp:483:14:483:27 | new[] | test.cpp:488:5:488:6 | xs | -| test.cpp:488:5:488:6 | xs | test.cpp:488:5:488:15 | access to array | -| test.cpp:488:5:488:15 | access to array | test.cpp:488:5:488:19 | Store: ... = ... | | test.cpp:494:14:494:31 | new[] | test.cpp:499:5:499:6 | xs | | test.cpp:505:14:505:31 | new[] | test.cpp:510:5:510:6 | xs | | test.cpp:516:14:516:31 | new[] | test.cpp:521:5:521:6 | xs | @@ -1174,16 +1164,10 @@ nodes | test.cpp:407:7:407:8 | xs indirection | semmle.label | xs indirection | | test.cpp:417:16:417:33 | new[] | semmle.label | new[] | | test.cpp:419:7:419:8 | xs | semmle.label | xs | -| test.cpp:419:7:419:11 | access to array | semmle.label | access to array | -| test.cpp:419:7:419:15 | Store: ... = ... | semmle.label | Store: ... = ... | | test.cpp:427:14:427:27 | new[] | semmle.label | new[] | | test.cpp:433:5:433:6 | xs | semmle.label | xs | -| test.cpp:433:5:433:17 | access to array | semmle.label | access to array | -| test.cpp:433:5:433:21 | Store: ... = ... | semmle.label | Store: ... = ... | | test.cpp:439:14:439:27 | new[] | semmle.label | new[] | | test.cpp:444:5:444:6 | xs | semmle.label | xs | -| test.cpp:444:5:444:15 | access to array | semmle.label | access to array | -| test.cpp:444:5:444:19 | Store: ... = ... | semmle.label | Store: ... = ... | | test.cpp:450:14:450:27 | new[] | semmle.label | new[] | | test.cpp:455:5:455:6 | xs | semmle.label | xs | | test.cpp:455:5:455:15 | access to array | semmle.label | access to array | @@ -1194,12 +1178,8 @@ nodes | test.cpp:466:5:466:19 | Store: ... = ... | semmle.label | Store: ... = ... | | test.cpp:472:14:472:27 | new[] | semmle.label | new[] | | test.cpp:477:5:477:6 | xs | semmle.label | xs | -| test.cpp:477:5:477:15 | access to array | semmle.label | access to array | -| test.cpp:477:5:477:19 | Store: ... = ... | semmle.label | Store: ... = ... | | test.cpp:483:14:483:27 | new[] | semmle.label | new[] | | test.cpp:488:5:488:6 | xs | semmle.label | xs | -| test.cpp:488:5:488:15 | access to array | semmle.label | access to array | -| test.cpp:488:5:488:19 | Store: ... = ... | semmle.label | Store: ... = ... | | test.cpp:494:14:494:31 | new[] | semmle.label | new[] | | test.cpp:499:5:499:6 | xs | semmle.label | xs | | test.cpp:505:14:505:31 | new[] | semmle.label | new[] | @@ -1242,11 +1222,6 @@ subpaths | test.cpp:384:13:384:16 | Load: * ... | test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:377:14:377:27 | new[] | new[] | test.cpp:378:20:378:23 | size | size | | test.cpp:395:5:395:13 | Store: ... = ... | test.cpp:388:14:388:27 | new[] | test.cpp:395:5:395:13 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:388:14:388:27 | new[] | new[] | test.cpp:389:19:389:22 | size | size | | test.cpp:407:3:407:22 | Store: ... = ... | test.cpp:404:12:404:25 | new[] | test.cpp:407:3:407:22 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:404:12:404:25 | new[] | new[] | test.cpp:407:10:407:17 | ... - ... | ... - ... | -| test.cpp:419:7:419:15 | Store: ... = ... | test.cpp:417:16:417:33 | new[] | test.cpp:419:7:419:15 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:417:16:417:33 | new[] | new[] | test.cpp:419:10:419:10 | i | i | -| test.cpp:433:5:433:21 | Store: ... = ... | test.cpp:427:14:427:27 | new[] | test.cpp:433:5:433:21 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:427:14:427:27 | new[] | new[] | test.cpp:433:8:433:16 | ... ++ | ... ++ | -| test.cpp:444:5:444:19 | Store: ... = ... | test.cpp:439:14:439:27 | new[] | test.cpp:444:5:444:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:439:14:439:27 | new[] | new[] | test.cpp:444:8:444:14 | src_pos | src_pos | | test.cpp:455:5:455:19 | Store: ... = ... | test.cpp:450:14:450:27 | new[] | test.cpp:455:5:455:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:450:14:450:27 | new[] | new[] | test.cpp:455:8:455:14 | src_pos | src_pos | | test.cpp:466:5:466:19 | Store: ... = ... | test.cpp:461:14:461:27 | new[] | test.cpp:466:5:466:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:461:14:461:27 | new[] | new[] | test.cpp:466:8:466:14 | src_pos | src_pos | -| test.cpp:477:5:477:19 | Store: ... = ... | test.cpp:472:14:472:27 | new[] | test.cpp:477:5:477:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:472:14:472:27 | new[] | new[] | test.cpp:477:8:477:14 | src_pos | src_pos | -| test.cpp:488:5:488:19 | Store: ... = ... | test.cpp:483:14:483:27 | new[] | test.cpp:488:5:488:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:483:14:483:27 | new[] | new[] | test.cpp:488:8:488:14 | src_pos | src_pos | | test.cpp:554:5:554:19 | Store: ... = ... | test.cpp:549:14:549:31 | new[] | test.cpp:554:5:554:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:549:14:549:31 | new[] | new[] | test.cpp:554:8:554:14 | src_pos | src_pos | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp index 3fd047fa180..1ff924f95a3 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp @@ -416,7 +416,7 @@ void test30(int *size) new_size = tmp_size + 1; char *xs = new char[new_size]; for (int i = 0; i < new_size; i++) { - xs[i] = 0; // GOOD [FALSE POSITIVE] + xs[i] = 0; // GOOD } } *size = new_size; @@ -430,7 +430,7 @@ void test31(unsigned size, unsigned src_pos) } unsigned dst_pos = src_pos; if(dst_pos < size - 3) { - xs[dst_pos++] = 0; // GOOD [FALSE POSITIVE] + xs[dst_pos++] = 0; // GOOD } } @@ -441,7 +441,7 @@ void test31_simple1(unsigned size, unsigned src_pos) src_pos = size; } if(src_pos < size) { - xs[src_pos] = 0; // GOOD [FALSE POSITIVE] + xs[src_pos] = 0; // GOOD } } @@ -474,7 +474,7 @@ void test31_simple4(unsigned size, unsigned src_pos) src_pos = size; } if(src_pos < size - 1) { - xs[src_pos] = 0; // GOOD [FALSE POSITIVE] + xs[src_pos] = 0; // GOOD } } @@ -485,7 +485,7 @@ void test31_simple5(unsigned size, unsigned src_pos) src_pos = size; } if(src_pos + 1 < size) { - xs[src_pos] = 0; // GOOD [FALSE POSITIVE] + xs[src_pos] = 0; // GOOD } } From e0f5c584b976597982a76a86ac9145c41197b824 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 24 Jun 2023 19:38:22 +0100 Subject: [PATCH 308/364] C++: Fix Code Scanning error. --- .../experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql index a202f3ed380..4249f3a12b9 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -131,8 +131,8 @@ module Barrier2 { } Instruction getABarrierInstruction(FlowState2 state) { - exists(IRGuardCondition g, Operand right, ValueNumber value, boolean edge | - operandGuardChecks(g, value.getAUse(), right, state, edge) and + exists(IRGuardCondition g, ValueNumber value, boolean edge | + operandGuardChecks(g, value.getAUse(), _, state, edge) and result = value.getAnInstruction() and g.controls(result.getBlock(), edge) ) From e32f7d84a5303da643fe4eb398ad2568cb57949c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sun, 25 Jun 2023 00:35:43 +0100 Subject: [PATCH 309/364] C++: Speed up analysis on 'Samate' by avoiding the 'Variable' column in the dataflow stages of the query. --- .../CWE/CWE-193/ConstantSizeArrayOffByOne.ql | 81 ++++++++++++------- .../ConstantSizeArrayOffByOne.expected | 5 ++ 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql index 9a17d4c37ac..b3258a6e627 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql @@ -78,28 +78,39 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string ) } +predicate arrayTypeCand(ArrayType arrayType) { any(Variable v).getUnspecifiedType() = arrayType } + pragma[nomagic] predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int arraySize) { + arrayTypeCand(arr) and arr.getBaseType().getSize() = baseTypeSize and arr.getArraySize() = arraySize } -predicate pointerArithOverflow0( - PointerArithmeticInstruction pai, Variable v, int size, int bound, int delta -) { - not v.getNamespace() instanceof StdNamespace and - arrayTypeHasSizes(v.getUnspecifiedType(), pai.getElementSize(), size) and - semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), bound, true, _) and +bindingset[pai] +pragma[inline_late] +predicate constantUpperBounded(PointerArithmeticInstruction pai, int delta) { + semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), delta, true, _) +} + +bindingset[pai, size] +predicate pointerArithOverflow0Impl(PointerArithmeticInstruction pai, int size, int bound, int delta) { + constantUpperBounded(pai, bound) and delta = bound - size and delta >= 0 and size != 0 and size != 1 } +predicate pointerArithOverflow0(PointerArithmeticInstruction pai, int delta) { + exists(int size, int bound | + arrayTypeHasSizes(_, pai.getElementSize(), size) and + pointerArithOverflow0Impl(pai, size, bound, delta) + ) +} + module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { - pointerArithOverflow0(source.asInstruction(), _, _, _, _) - } + predicate isSource(DataFlow::Node source) { pointerArithOverflow0(source.asInstruction(), _) } predicate isBarrierIn(DataFlow::Node node) { isSource(node) } @@ -110,30 +121,38 @@ module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig { module PointerArithmeticToDerefFlow = DataFlow::Global; -predicate pointerArithOverflow( - PointerArithmeticInstruction pai, Variable v, int size, int bound, int delta -) { - pointerArithOverflow0(pai, v, size, bound, delta) and +predicate pointerArithOverflow(PointerArithmeticInstruction pai, int delta) { + pointerArithOverflow0(pai, delta) and PointerArithmeticToDerefFlow::flow(DataFlow::instructionNode(pai), _) } +bindingset[v] +predicate finalPointerArithOverflow(Variable v, PointerArithmeticInstruction pai, int delta) { + exists(int size | + arrayTypeHasSizes(pragma[only_bind_out](v.getUnspecifiedType()), pai.getElementSize(), size) and + pointerArithOverflow0Impl(pai, size, _, delta) + ) +} + +predicate isSourceImpl(DataFlow::Node source, Variable v) { + ( + source.asInstruction().(FieldAddressInstruction).getField() = v + or + source.asInstruction().(VariableAddressInstruction).getAstVariable() = v + ) and + exists(v.getUnspecifiedType().(ArrayType).getArraySize()) +} + module ArrayAddressToDerefConfig implements DataFlow::StateConfigSig { newtype FlowState = - additional TArray(Variable v) { pointerArithOverflow(_, v, _, _, _) } or + additional TArray() or additional TOverflowArithmetic(PointerArithmeticInstruction pai) { - pointerArithOverflow(pai, _, _, _, _) + pointerArithOverflow(pai, _) } predicate isSource(DataFlow::Node source, FlowState state) { - exists(Variable v | - ( - source.asInstruction().(FieldAddressInstruction).getField() = v - or - source.asInstruction().(VariableAddressInstruction).getAstVariable() = v - ) and - exists(v.getUnspecifiedType().(ArrayType).getArraySize()) and - state = TArray(v) - ) + isSourceImpl(source, _) and + state = TArray() } predicate isSink(DataFlow::Node sink, FlowState state) { @@ -152,12 +171,12 @@ module ArrayAddressToDerefConfig implements DataFlow::StateConfigSig { predicate isAdditionalFlowStep( DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2 ) { - exists(PointerArithmeticInstruction pai, Variable v | - state1 = TArray(v) and + exists(PointerArithmeticInstruction pai | + state1 = TArray() and state2 = TOverflowArithmetic(pai) and pai.getLeft() = node1.asInstruction() and node2.asInstruction() = pai and - pointerArithOverflow(pai, v, _, _, _) + pointerArithOverflow(pai, _) ) } } @@ -168,11 +187,11 @@ from Variable v, ArrayAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai, ArrayAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta where - ArrayAddressToDerefFlow::flowPath(source, sink) and + ArrayAddressToDerefFlow::flowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and - source.getState() = ArrayAddressToDerefConfig::TArray(v) and - sink.getState() = ArrayAddressToDerefConfig::TOverflowArithmetic(pai) and - pointerArithOverflow(pai, v, _, _, delta) + pragma[only_bind_out](sink.getState()) = ArrayAddressToDerefConfig::TOverflowArithmetic(pai) and + isSourceImpl(source.getNode(), v) and + finalPointerArithOverflow(v, pai, delta) select pai, source, sink, "This pointer arithmetic may have an off-by-" + (delta + 1) + " error allowing it to overrun $@ at this $@.", v, v.getName(), deref, operation diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected index 88e32ccf921..c85ad8f95c1 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected @@ -11,6 +11,8 @@ edges | test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... | | test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p | | test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf | +| test.cpp:85:34:85:36 | buf | test.cpp:87:5:87:31 | access to array | +| test.cpp:85:34:85:36 | buf | test.cpp:88:5:88:27 | access to array | | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | | test.cpp:134:25:134:27 | arr | test.cpp:136:9:136:16 | ... += ... | | test.cpp:136:9:136:16 | ... += ... | test.cpp:138:13:138:15 | arr | @@ -38,6 +40,9 @@ nodes | test.cpp:77:32:77:34 | buf | semmle.label | buf | | test.cpp:79:27:79:34 | buf | semmle.label | buf | | test.cpp:79:32:79:34 | buf | semmle.label | buf | +| test.cpp:85:34:85:36 | buf | semmle.label | buf | +| test.cpp:87:5:87:31 | access to array | semmle.label | access to array | +| test.cpp:88:5:88:27 | access to array | semmle.label | access to array | | test.cpp:128:9:128:11 | arr | semmle.label | arr | | test.cpp:128:9:128:14 | access to array | semmle.label | access to array | | test.cpp:134:25:134:27 | arr | semmle.label | arr | From 55280e523a7cd9ea55955312b382ce8dcc00b75f Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 26 Jun 2023 11:14:31 +0200 Subject: [PATCH 310/364] Update java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll --- .../semmle/code/java/security/UnsafeDeserializationQuery.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll b/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll index ee553c5f7bd..550b778d8db 100644 --- a/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll +++ b/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll @@ -29,7 +29,7 @@ private class ObjectInputStreamReadObjectMethod extends Method { } /** - * A type coming from `ObjectInputStream` that makes it safe to deserialize untrusted data. + * A type extending `ObjectInputStream` that makes it safe to deserialize untrusted data. * * * See https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/serialization/ValidatingObjectInputStream.html * * See https://github.com/ikkisoft/SerialKiller From 6cb03190fa26adb4dc73e0026facc0556937cbf5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 26 Jun 2023 11:43:51 +0200 Subject: [PATCH 311/364] Python: Updates from inline test being parameterized --- .../dataflow/model-summaries/InlineTaintTest.expected | 3 ++- .../experimental/dataflow/model-summaries/InlineTaintTest.ql | 1 + .../dataflow/model-summaries/NormalDataflowTest.expected | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.expected b/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.expected index 79d760d87f4..4a72c551661 100644 --- a/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.expected +++ b/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.expected @@ -1,3 +1,4 @@ +failures argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing -failures +testFailures diff --git a/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ql b/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ql index f7f84cb8479..551266d7455 100644 --- a/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ql +++ b/python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ql @@ -1,3 +1,4 @@ import python private import TestSummaries import experimental.meta.InlineTaintTest +import MakeInlineTaintTest diff --git a/python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.expected index 3875da4e143..04431311999 100644 --- a/python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.expected +++ b/python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink failures +testFailures From 257f9912dd6eb292860fb38874396edc2d57d361 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 26 Jun 2023 12:00:15 +0200 Subject: [PATCH 312/364] Python: Remove one more unnecessary taint test --- .../experimental/dataflow/model-summaries/model_summaries.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py index 64909fcd741..ee02918b079 100644 --- a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py +++ b/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py @@ -44,8 +44,6 @@ SINK(via_lambda[0]) # $ flow="SOURCE, l:-1 -> via_lambda[0]" not_via_lambda = MS_apply_lambda(lambda x: 1, SOURCE) SINK_F(not_via_lambda) -untainted_lambda = MS_apply_lambda(lambda x: 1, TAINTED_STRING) -ensure_not_tainted(untainted_lambda) # Collection summaries via_reversed = MS_reversed([SOURCE]) From 458522a656bf436be5f9ea12233a2cfc13aad98b Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 26 Jun 2023 12:11:03 +0200 Subject: [PATCH 313/364] C++: Implement `clearsContent` for IR dataflow --- .../ir/dataflow/internal/DataFlowPrivate.qll | 70 ++++- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 46 ++- .../ArrayAccessProductFlow.expected | 14 +- .../InvalidPointerDeref.expected | 27 +- .../CWE/CWE-193/pointer-deref/test.cpp | 2 +- .../dataflow/fields/clearning.cpp | 182 ++++++++++++ .../fields/dataflow-consistency.expected | 29 ++ .../fields/dataflow-ir-consistency.expected | 11 + .../dataflow/fields/ir-path-flow.expected | 270 +++++++++++++++++- .../fields/partial-definition-diff.expected | 60 ++++ .../fields/partial-definition-ir.expected | 84 ++++++ .../fields/partial-definition.expected | 86 ++++++ .../dataflow/fields/path-flow.expected | 90 ++++++ .../SAMATE/OverrunWriteProductFlow.expected | 28 +- 14 files changed, 944 insertions(+), 55 deletions(-) create mode 100644 cpp/ql/test/library-tests/dataflow/fields/clearning.cpp diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 6715b67c382..85a4a224e52 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -651,13 +651,16 @@ predicate jumpStep(Node n1, Node n2) { * 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`. + * + * The boolean `certain` is true if the destination address does not involve + * any pointer arithmetic, and false otherwise. */ -predicate storeStep(Node node1, Content c, PostFieldUpdateNode node2) { +predicate storeStepImpl(Node node1, Content c, PostFieldUpdateNode node2, boolean certain) { exists(int indirectionIndex1, int numberOfLoads, StoreInstruction store | nodeHasInstruction(node1, store, pragma[only_bind_into](indirectionIndex1)) and node2.getIndirectionIndex() = 1 and numberOfLoadsFromOperand(node2.getFieldAddress(), store.getDestinationAddressOperand(), - numberOfLoads) + numberOfLoads, certain) | exists(FieldContent fc | fc = c | fc.getField() = node2.getUpdatedField() and @@ -671,21 +674,34 @@ predicate storeStep(Node node1, Content c, PostFieldUpdateNode 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 c, PostFieldUpdateNode node2) { + storeStepImpl(node1, c, node2, _) +} + /** * Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like * operations and exactly `n` `LoadInstruction` operations. */ -private predicate numberOfLoadsFromOperandRec(Operand operandFrom, Operand operandTo, int ind) { +private predicate numberOfLoadsFromOperandRec( + Operand operandFrom, Operand operandTo, int ind, boolean certain +) { exists(Instruction load | Ssa::isDereference(load, operandFrom) | - operandTo = operandFrom and ind = 0 + operandTo = operandFrom and ind = 0 and certain = true or - numberOfLoadsFromOperand(load.getAUse(), operandTo, ind - 1) + numberOfLoadsFromOperand(load.getAUse(), operandTo, ind - 1, certain) ) or - exists(Operand op, Instruction instr | + exists(Operand op, Instruction instr, boolean isPointerArith, boolean certain0 | instr = op.getDef() and - conversionFlow(operandFrom, instr, _, _) and - numberOfLoadsFromOperand(op, operandTo, ind) + conversionFlow(operandFrom, instr, isPointerArith, _) and + numberOfLoadsFromOperand(op, operandTo, ind, certain0) + | + if isPointerArith = true then certain = false else certain = certain0 ) } @@ -693,13 +709,16 @@ private predicate numberOfLoadsFromOperandRec(Operand operandFrom, Operand opera * Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like * operations and exactly `n` `LoadInstruction` operations. */ -private predicate numberOfLoadsFromOperand(Operand operandFrom, Operand operandTo, int n) { - numberOfLoadsFromOperandRec(operandFrom, operandTo, n) +private predicate numberOfLoadsFromOperand( + Operand operandFrom, Operand operandTo, int n, boolean certain +) { + numberOfLoadsFromOperandRec(operandFrom, operandTo, n, certain) or not Ssa::isDereference(_, operandFrom) and not conversionFlow(operandFrom, _, _, _) and operandFrom = operandTo and - n = 0 + n = 0 and + certain = true } // Needed to join on both an operand and an index at the same time. @@ -729,7 +748,7 @@ predicate readStep(Node node1, Content c, Node node2) { // The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct // in `storeStep`. nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and - numberOfLoadsFromOperand(fa1, operand, numberOfLoads) + numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) | exists(FieldContent fc | fc = c | fc.getField() = fa1.getField() and @@ -747,7 +766,32 @@ predicate readStep(Node node1, Content c, Node node2) { * Holds if values stored inside content `c` are cleared at node `n`. */ predicate clearsContent(Node n, Content c) { - none() // stub implementation + n = + any(PostUpdateNode pun, Content d | d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) | pun) + .getPreUpdateNode() and + ( + // The crement operations and pointer addition and subtraction self-assign. We do not + // want to clear the contents if it is indirectly pointed at by any of these operations, + // as part of the contents might still be accessible afterwards. If there is no such + // indirection clearing the contents is safe. + not exists(Operand op, Cpp::Operation p | + n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and + ( + p instanceof Cpp::AssignPointerAddExpr or + p instanceof Cpp::AssignPointerSubExpr or + p instanceof Cpp::CrementOperation + ) + | + p.getAnOperand() = op.getUse().getAst() + ) + or + not exists(PostUpdateNode pun, Content d | + d.impliesClearOf(c) and + storeStepImpl(_, d, pun, true) and + c.getIndirectionIndex() > d.getIndirectionIndex() and + pun.getPreUpdateNode() = n + ) + ) } /** diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 4cf5cd65fa8..11a4b817dbf 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -1832,6 +1832,26 @@ class Content extends TContent { predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 } + + /** + * INTERNAL: Do not use. + * + * Holds if a write to this `Content` implies that `c` is + * also cleared. + * + * For example, a write to a field `f` implies that any content of + * the form `*f` is also cleared. + */ + abstract predicate impliesClearOf(Content c); + + abstract int getIndirectionIndex(); +} + +predicate foo(FieldContent f) { + exists(int i, Field ff | + i = f.getIndirectionIndex() and + ff = f.getField() + ) } /** A reference through a non-union instance field. */ @@ -1850,9 +1870,19 @@ class FieldContent extends Content, TFieldContent { Field getField() { result = f } pragma[inline] - int getIndirectionIndex() { + override int getIndirectionIndex() { pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex) } + + override predicate impliesClearOf(Content c) { + exists(FieldContent fc | + fc = c and + fc.getField() = f and + // If `this` is `f` then `c` is cleared if it's of the + // form `*f`, `**f`, etc. + fc.getIndirectionIndex() >= indirectionIndex + ) + } } /** A reference through an instance field of a union. */ @@ -1877,9 +1907,21 @@ class UnionContent extends Content, TUnionContent { /** Gets the indirection index of this `UnionContent`. */ pragma[inline] - int getIndirectionIndex() { + override int getIndirectionIndex() { pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex) } + + override predicate impliesClearOf(Content c) { + exists(UnionContent uc | + uc = c and + uc.getUnion() = u and + // If `this` is `u` then `c` is cleared if it's of the + // form `*u`, `**u`, etc. (and we ignore `bytes` because + // we know the entire union is overwritten because it's a + // union). + uc.getIndirectionIndex() >= indirectionIndex + ) + } } /** diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected index 820c48447ff..dbd71611d81 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/array-access/ArrayAccessProductFlow.expected @@ -4,8 +4,9 @@ edges | test.cpp:19:9:19:16 | mk_array indirection [p] | test.cpp:28:19:28:26 | call to mk_array [p] | | test.cpp:19:9:19:16 | mk_array indirection [p] | test.cpp:50:18:50:25 | call to mk_array [p] | | test.cpp:21:5:21:24 | ... = ... | test.cpp:21:9:21:9 | arr indirection [post update] [p] | -| test.cpp:21:9:21:9 | arr indirection [post update] [p] | test.cpp:19:9:19:16 | mk_array indirection [p] | +| test.cpp:21:9:21:9 | arr indirection [post update] [p] | test.cpp:22:5:22:7 | arr indirection [p] | | test.cpp:21:13:21:18 | call to malloc | test.cpp:21:5:21:24 | ... = ... | +| test.cpp:22:5:22:7 | arr indirection [p] | test.cpp:19:9:19:16 | mk_array indirection [p] | | test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:31:9:31:11 | arr indirection [p] | | test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:35:9:35:11 | arr indirection [p] | | test.cpp:31:9:31:11 | arr indirection [p] | test.cpp:31:13:31:13 | p indirection | @@ -20,9 +21,10 @@ edges | test.cpp:45:13:45:13 | p indirection | test.cpp:45:13:45:13 | p | | test.cpp:50:18:50:25 | call to mk_array [p] | test.cpp:39:27:39:29 | arr [p] | | test.cpp:55:5:55:24 | ... = ... | test.cpp:55:9:55:9 | arr indirection [post update] [p] | -| test.cpp:55:9:55:9 | arr indirection [post update] [p] | test.cpp:59:9:59:11 | arr indirection [p] | -| test.cpp:55:9:55:9 | arr indirection [post update] [p] | test.cpp:63:9:63:11 | arr indirection [p] | +| test.cpp:55:9:55:9 | arr indirection [post update] [p] | test.cpp:56:5:56:7 | arr indirection [p] | | test.cpp:55:13:55:18 | call to malloc | test.cpp:55:5:55:24 | ... = ... | +| test.cpp:56:5:56:7 | arr indirection [p] | test.cpp:59:9:59:11 | arr indirection [p] | +| test.cpp:56:5:56:7 | arr indirection [p] | test.cpp:63:9:63:11 | arr indirection [p] | | test.cpp:59:9:59:11 | arr indirection [p] | test.cpp:59:13:59:13 | p indirection | | test.cpp:59:13:59:13 | p indirection | test.cpp:59:13:59:13 | p | | test.cpp:63:9:63:11 | arr indirection [p] | test.cpp:63:13:63:13 | p indirection | @@ -30,8 +32,9 @@ edges | test.cpp:67:10:67:19 | mk_array_p indirection [p] | test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | | test.cpp:67:10:67:19 | mk_array_p indirection [p] | test.cpp:98:18:98:27 | call to mk_array_p indirection [p] | | test.cpp:69:5:69:25 | ... = ... | test.cpp:69:10:69:10 | arr indirection [post update] [p] | -| test.cpp:69:10:69:10 | arr indirection [post update] [p] | test.cpp:67:10:67:19 | mk_array_p indirection [p] | +| test.cpp:69:10:69:10 | arr indirection [post update] [p] | test.cpp:70:5:70:7 | arr indirection [p] | | test.cpp:69:14:69:19 | call to malloc | test.cpp:69:5:69:25 | ... = ... | +| test.cpp:70:5:70:7 | arr indirection [p] | test.cpp:67:10:67:19 | mk_array_p indirection [p] | | test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:79:9:79:11 | arr indirection [p] | | test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:83:9:83:11 | arr indirection [p] | | test.cpp:79:9:79:11 | arr indirection [p] | test.cpp:79:14:79:14 | p indirection | @@ -53,6 +56,7 @@ nodes | test.cpp:21:5:21:24 | ... = ... | semmle.label | ... = ... | | test.cpp:21:9:21:9 | arr indirection [post update] [p] | semmle.label | arr indirection [post update] [p] | | test.cpp:21:13:21:18 | call to malloc | semmle.label | call to malloc | +| test.cpp:22:5:22:7 | arr indirection [p] | semmle.label | arr indirection [p] | | test.cpp:28:19:28:26 | call to mk_array [p] | semmle.label | call to mk_array [p] | | test.cpp:31:9:31:11 | arr indirection [p] | semmle.label | arr indirection [p] | | test.cpp:31:13:31:13 | p | semmle.label | p | @@ -71,6 +75,7 @@ nodes | test.cpp:55:5:55:24 | ... = ... | semmle.label | ... = ... | | test.cpp:55:9:55:9 | arr indirection [post update] [p] | semmle.label | arr indirection [post update] [p] | | test.cpp:55:13:55:18 | call to malloc | semmle.label | call to malloc | +| test.cpp:56:5:56:7 | arr indirection [p] | semmle.label | arr indirection [p] | | test.cpp:59:9:59:11 | arr indirection [p] | semmle.label | arr indirection [p] | | test.cpp:59:13:59:13 | p | semmle.label | p | | test.cpp:59:13:59:13 | p indirection | semmle.label | p indirection | @@ -81,6 +86,7 @@ nodes | test.cpp:69:5:69:25 | ... = ... | semmle.label | ... = ... | | test.cpp:69:10:69:10 | arr indirection [post update] [p] | semmle.label | arr indirection [post update] [p] | | test.cpp:69:14:69:19 | call to malloc | semmle.label | call to malloc | +| test.cpp:70:5:70:7 | arr indirection [p] | semmle.label | arr indirection [p] | | test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | semmle.label | call to mk_array_p indirection [p] | | test.cpp:79:9:79:11 | arr indirection [p] | semmle.label | arr indirection [p] | | test.cpp:79:14:79:14 | p | semmle.label | p | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected index 7c27659de1f..d23f1d16130 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected @@ -380,9 +380,10 @@ edges | test.cpp:80:9:80:16 | mk_array indirection [end] | test.cpp:89:19:89:26 | call to mk_array [end] | | test.cpp:80:9:80:16 | mk_array indirection [end] | test.cpp:119:18:119:25 | call to mk_array [end] | | test.cpp:82:5:82:28 | ... = ... | test.cpp:82:9:82:13 | arr indirection [post update] [begin] | -| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | test.cpp:80:9:80:16 | mk_array indirection [begin] | +| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | test.cpp:83:5:83:7 | arr indirection [begin] | | test.cpp:82:9:82:13 | arr indirection [post update] [begin] | test.cpp:83:15:83:17 | arr indirection [begin] | | test.cpp:82:17:82:22 | call to malloc | test.cpp:82:5:82:28 | ... = ... | +| test.cpp:83:5:83:7 | arr indirection [begin] | test.cpp:80:9:80:16 | mk_array indirection [begin] | | test.cpp:83:5:83:30 | ... = ... | test.cpp:83:9:83:11 | arr indirection [post update] [end] | | test.cpp:83:9:83:11 | arr indirection [post update] [end] | test.cpp:80:9:80:16 | mk_array indirection [end] | | test.cpp:83:15:83:17 | arr indirection [begin] | test.cpp:83:19:83:23 | begin indirection | @@ -455,9 +456,10 @@ edges | test.cpp:124:15:124:20 | call to malloc | test.cpp:125:5:125:17 | ... = ... | | test.cpp:124:15:124:20 | call to malloc | test.cpp:126:15:126:15 | p | | test.cpp:125:5:125:17 | ... = ... | test.cpp:125:9:125:13 | arr indirection [post update] [begin] | -| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | test.cpp:129:11:129:13 | arr indirection [begin] | -| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | test.cpp:133:11:133:13 | arr indirection [begin] | -| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | test.cpp:137:11:137:13 | arr indirection [begin] | +| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | test.cpp:126:5:126:7 | arr indirection [begin] | +| test.cpp:126:5:126:7 | arr indirection [begin] | test.cpp:129:11:129:13 | arr indirection [begin] | +| test.cpp:126:5:126:7 | arr indirection [begin] | test.cpp:133:11:133:13 | arr indirection [begin] | +| test.cpp:126:5:126:7 | arr indirection [begin] | test.cpp:137:11:137:13 | arr indirection [begin] | | test.cpp:129:11:129:13 | arr indirection [begin] | test.cpp:129:15:129:19 | begin indirection | | test.cpp:129:15:129:19 | begin indirection | test.cpp:129:15:129:19 | begin | | test.cpp:133:11:133:13 | arr indirection [begin] | test.cpp:133:15:133:19 | begin indirection | @@ -469,9 +471,10 @@ edges | test.cpp:141:10:141:19 | mk_array_p indirection [end] | test.cpp:150:20:150:29 | call to mk_array_p indirection [end] | | test.cpp:141:10:141:19 | mk_array_p indirection [end] | test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | | test.cpp:143:5:143:29 | ... = ... | test.cpp:143:10:143:14 | arr indirection [post update] [begin] | -| test.cpp:143:10:143:14 | arr indirection [post update] [begin] | test.cpp:141:10:141:19 | mk_array_p indirection [begin] | +| test.cpp:143:10:143:14 | arr indirection [post update] [begin] | test.cpp:144:5:144:7 | arr indirection [begin] | | test.cpp:143:10:143:14 | arr indirection [post update] [begin] | test.cpp:144:16:144:18 | arr indirection [begin] | | test.cpp:143:18:143:23 | call to malloc | test.cpp:143:5:143:29 | ... = ... | +| test.cpp:144:5:144:7 | arr indirection [begin] | test.cpp:141:10:141:19 | mk_array_p indirection [begin] | | test.cpp:144:5:144:32 | ... = ... | test.cpp:144:10:144:12 | arr indirection [post update] [end] | | test.cpp:144:10:144:12 | arr indirection [post update] [end] | test.cpp:141:10:141:19 | mk_array_p indirection [end] | | test.cpp:144:16:144:18 | arr indirection [begin] | test.cpp:144:21:144:25 | begin indirection | @@ -772,15 +775,10 @@ edges | test.cpp:393:9:393:10 | xs | test.cpp:395:5:395:13 | Store: ... = ... | | test.cpp:393:9:393:10 | xs | test.cpp:395:5:395:13 | Store: ... = ... | | test.cpp:395:5:395:6 | xs | test.cpp:395:5:395:13 | Store: ... = ... | -| test.cpp:404:3:404:25 | ... = ... | test.cpp:404:7:404:8 | val indirection [post update] [xs] | -| test.cpp:404:7:404:8 | val indirection [post update] [xs] | test.cpp:407:3:407:5 | val indirection [xs] | -| test.cpp:404:12:404:25 | new[] | test.cpp:404:3:404:25 | ... = ... | | test.cpp:406:3:406:25 | ... = ... | test.cpp:406:7:406:8 | val indirection [post update] [xs] | | test.cpp:406:7:406:8 | val indirection [post update] [xs] | test.cpp:407:3:407:5 | val indirection [xs] | | test.cpp:406:12:406:25 | new[] | test.cpp:406:3:406:25 | ... = ... | | test.cpp:407:3:407:5 | val indirection [xs] | test.cpp:407:7:407:8 | xs indirection | -| test.cpp:407:3:407:18 | access to array | test.cpp:407:3:407:22 | Store: ... = ... | -| test.cpp:407:7:407:8 | xs | test.cpp:407:3:407:18 | access to array | | test.cpp:407:7:407:8 | xs indirection | test.cpp:407:7:407:8 | xs | | test.cpp:417:16:417:33 | new[] | test.cpp:419:7:419:8 | xs | | test.cpp:419:7:419:8 | xs | test.cpp:419:7:419:11 | access to array | @@ -880,6 +878,7 @@ nodes | test.cpp:82:5:82:28 | ... = ... | semmle.label | ... = ... | | test.cpp:82:9:82:13 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] | | test.cpp:82:17:82:22 | call to malloc | semmle.label | call to malloc | +| test.cpp:83:5:83:7 | arr indirection [begin] | semmle.label | arr indirection [begin] | | test.cpp:83:5:83:30 | ... = ... | semmle.label | ... = ... | | test.cpp:83:9:83:11 | arr indirection [post update] [end] | semmle.label | arr indirection [post update] [end] | | test.cpp:83:15:83:17 | arr indirection [begin] | semmle.label | arr indirection [begin] | @@ -939,6 +938,7 @@ nodes | test.cpp:124:15:124:20 | call to malloc | semmle.label | call to malloc | | test.cpp:125:5:125:17 | ... = ... | semmle.label | ... = ... | | test.cpp:125:9:125:13 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] | +| test.cpp:126:5:126:7 | arr indirection [begin] | semmle.label | arr indirection [begin] | | test.cpp:126:15:126:15 | p | semmle.label | p | | test.cpp:129:11:129:13 | arr indirection [begin] | semmle.label | arr indirection [begin] | | test.cpp:129:15:129:19 | begin | semmle.label | begin | @@ -954,6 +954,7 @@ nodes | test.cpp:143:5:143:29 | ... = ... | semmle.label | ... = ... | | test.cpp:143:10:143:14 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] | | test.cpp:143:18:143:23 | call to malloc | semmle.label | call to malloc | +| test.cpp:144:5:144:7 | arr indirection [begin] | semmle.label | arr indirection [begin] | | test.cpp:144:5:144:32 | ... = ... | semmle.label | ... = ... | | test.cpp:144:10:144:12 | arr indirection [post update] [end] | semmle.label | arr indirection [post update] [end] | | test.cpp:144:16:144:18 | arr indirection [begin] | semmle.label | arr indirection [begin] | @@ -1138,15 +1139,10 @@ nodes | test.cpp:393:9:393:10 | xs | semmle.label | xs | | test.cpp:395:5:395:6 | xs | semmle.label | xs | | test.cpp:395:5:395:13 | Store: ... = ... | semmle.label | Store: ... = ... | -| test.cpp:404:3:404:25 | ... = ... | semmle.label | ... = ... | -| test.cpp:404:7:404:8 | val indirection [post update] [xs] | semmle.label | val indirection [post update] [xs] | -| test.cpp:404:12:404:25 | new[] | semmle.label | new[] | | test.cpp:406:3:406:25 | ... = ... | semmle.label | ... = ... | | test.cpp:406:7:406:8 | val indirection [post update] [xs] | semmle.label | val indirection [post update] [xs] | | test.cpp:406:12:406:25 | new[] | semmle.label | new[] | | test.cpp:407:3:407:5 | val indirection [xs] | semmle.label | val indirection [xs] | -| test.cpp:407:3:407:18 | access to array | semmle.label | access to array | -| test.cpp:407:3:407:22 | Store: ... = ... | semmle.label | Store: ... = ... | | test.cpp:407:7:407:8 | xs | semmle.label | xs | | test.cpp:407:7:407:8 | xs indirection | semmle.label | xs indirection | | test.cpp:417:16:417:33 | new[] | semmle.label | new[] | @@ -1184,6 +1180,5 @@ subpaths | test.cpp:372:15:372:16 | Load: * ... | test.cpp:363:14:363:27 | new[] | test.cpp:372:15:372:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:363:14:363:27 | new[] | new[] | test.cpp:365:19:365:22 | size | size | | test.cpp:384:13:384:16 | Load: * ... | test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:377:14:377:27 | new[] | new[] | test.cpp:378:20:378:23 | size | size | | test.cpp:395:5:395:13 | Store: ... = ... | test.cpp:388:14:388:27 | new[] | test.cpp:395:5:395:13 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:388:14:388:27 | new[] | new[] | test.cpp:389:19:389:22 | size | size | -| test.cpp:407:3:407:22 | Store: ... = ... | test.cpp:404:12:404:25 | new[] | test.cpp:407:3:407:22 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:404:12:404:25 | new[] | new[] | test.cpp:407:10:407:17 | ... - ... | ... - ... | | test.cpp:419:7:419:15 | Store: ... = ... | test.cpp:417:16:417:33 | new[] | test.cpp:419:7:419:15 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:417:16:417:33 | new[] | new[] | test.cpp:419:10:419:10 | i | i | | test.cpp:433:5:433:21 | Store: ... = ... | test.cpp:427:14:427:27 | new[] | test.cpp:433:5:433:21 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:427:14:427:27 | new[] | new[] | test.cpp:433:8:433:16 | ... ++ | ... ++ | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp index 4048c15be8b..01538c59efd 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp @@ -404,7 +404,7 @@ void test29(unsigned size) { val.xs = new char[size]; size++; val.xs = new char[size]; - val.xs[size - 1] = 0; // GOOD [FALSE POSITIVE] + val.xs[size - 1] = 0; // GOOD } void test30(int *size) diff --git a/cpp/ql/test/library-tests/dataflow/fields/clearning.cpp b/cpp/ql/test/library-tests/dataflow/fields/clearning.cpp new file mode 100644 index 00000000000..cdcc0c7afac --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/clearning.cpp @@ -0,0 +1,182 @@ +// We want a source of user input that can be both a pointer and a non-pointer. So we +// hack the testing a bit by providing an overload that takes a boolean to distinguish +// between the two while still satisfying the test requirement that the function must +// be named `user_input`. +int user_input(); +int* user_input(bool); +void sink(...); +void argument_source(int*); + +struct S { + int** x; +}; + +void test() +{ + { + S s; + **s.x = user_input(); + *s.x = 0; + sink(**s.x); // $ clean, as *s.x was overwritten and that contains the tainted **s.x + } + + { + S s; + **s.x = user_input(); + **s.x = 0; + sink(**s.x); // $ clean, as **s.x was overwritten and tainted + } + + { + S s; + *s.x = user_input(true); + **s.x = 0; + sink(*s.x); // $ ir // not clean, as **s.x was overwritten and is neither equal nor contains the tainted *s.x + } + + { + S s; + *s.x = user_input(true); + s.x = 0; + sink(*s.x); // clean, as s.x was overwritten and contains the tainted *s.x + } + + { + S s; + **s.x = user_input(); + s.x = 0; + sink(*s.x); // clean, as s.x was overwritten and contains the tainted **s.x + } + + { + S s; + *s.x = user_input(true); + s.x++; + sink(s.x); // $ SPURIOUS: ir ast // Cannot tell the difference with the whole array being tainted + } + + { + S s; + **s.x = user_input(); + s.x++; + sink(s.x); // $ SPURIOUS: ir // Cannot tell the difference with the whole array being tainted + } +} + +struct S2 +{ + int* val; +}; + +void test_uncertain_write_is_not_clear() +{ + S2 s; + argument_source(s.val); + s.val[10] = 0; + sink(*s.val); // $ ir MISSING: ast // not clean, as all elements of s.val are tainted and only one is overwitten +} + +void test_indirection_should_not_be_cleared_with_write_1() { + S2 s; + argument_source(s.val); // *s.val is tainted + s.val[0] = 0; + s.val = s.val + 1; + sink(*s.val); // $ ir MISSING: ast // not clean, as all elements of s.val are tainted, only one if overwritten, and the updated pointer still points to tainted elements +} + +void test_indirection_should_not_be_cleared_with_write_2() { + S2 s; + argument_source(s.val); // *s.val is tainted + *s.val++ = 0; + sink(*s.val); // $ ir MISSING: ast // not clean, as all elements of s.val are tainted, only one if overwritten, and the updated pointer still points to tainted elements +} + +void test_indirection_should_not_be_cleared_without_write_1() { + S2 s; + argument_source(s.val); // *s.val is tainted + s.val = s.val + 1; + sink(*s.val); // $ ir MISSING: ast // not clean, as all elements of s.val are tainted and the updated pointer still points to tainted elements +} + +void test_indirection_should_not_be_cleared_without_write_2() { + S2 s; + argument_source(s.val); // *s.val is tainted + s.val++; + sink(*s.val); // $ ir MISSING: ast // not clean, as all elements of s.val are tainted and the updated pointer still points to tainted elements +} + +void test_indirection_should_not_be_cleared_without_write_3() { + S2 s; + argument_source(s.val); // *s.val is tainted + ++s.val; + sink(*s.val); // $ ir MISSING: ast // not clean as the pointer is only moved to the next tainted element +} + +void test_indirection_should_not_be_cleared_without_write_4() { + S2 s; + argument_source(s.val); // *s.val is tainted + s.val += 1; + sink(*s.val); // $ ir MISSING: ast // not clean as the pointer is only moved to the next tainted element +} + +void test_direct_should_be_cleared() { + S2 s; + s.val = user_input(true); // s.val is tainted + s.val += 1; + sink(s.val); // $ SPURIOUS: ast // clean, as s.val was overwritten and tainted +} + +void test_direct_should_be_cleared_post() { + S2 s; + s.val = user_input(true); // s.val is tainted + s.val++; + sink(s.val); // $ SPURIOUS: ast // clean, as s.val was overwritten and tainted +} + +void test_direct_should_be_cleared_pre() { + S2 s; + s.val = user_input(true); // s.val is tainted + ++s.val; + sink(s.val); // $ SPURIOUS: ast // // clean, as s.x was overwritten and tainted +} + +struct S3 +{ + int val; +}; + +void test_direct() { + { + S3 s; + s.val = user_input(); + sink(s.val); // $ ir ast + } + + { + S3 s; + s.val = user_input(); + s.val = 0; + sink(s.val); // $ SPURIOUS: ast // clean + } + + { + S3 s; + s.val = user_input(); + s.val++; + sink(s.val); // $ SPURIOUS: ast // clean + } + + { + S3 s; + s.val = user_input(); + s.val += 1; + sink(s.val); // $ SPURIOUS: ast // clean + } + + { + S3 s; + s.val = user_input(); + s.val = s.val + 1; + sink(s.val); // $ SPURIOUS: ast // clean + } +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index 71c84a0446d..e8f54d3d7ba 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -43,6 +43,9 @@ argHasPostUpdate | arrays.cpp:10:8:10:15 | * ... | ArgumentNode is missing PostUpdateNode. | | arrays.cpp:16:8:16:13 | access to array | ArgumentNode is missing PostUpdateNode. | | arrays.cpp:17:8:17:13 | access to array | ArgumentNode is missing PostUpdateNode. | +| clearning.cpp:34:8:34:11 | * ... | ArgumentNode is missing PostUpdateNode. | +| clearning.cpp:41:8:41:11 | * ... | ArgumentNode is missing PostUpdateNode. | +| clearning.cpp:48:8:48:11 | * ... | ArgumentNode is missing PostUpdateNode. | postWithInFlow | A.cpp:25:13:25:13 | c [post update] | PostUpdateNode should not be the target of local flow. | | A.cpp:27:28:27:28 | c [post update] | PostUpdateNode should not be the target of local flow. | @@ -123,6 +126,32 @@ postWithInFlow | by_reference.cpp:108:24:108:24 | a [inner post update] | PostUpdateNode should not be the target of local flow. | | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | | by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:19:3:19:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:19:6:19:6 | x [inner post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:32:3:32:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:32:6:32:6 | x [inner post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:39:3:39:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:39:6:39:6 | x [inner post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:40:5:40:5 | x [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:47:5:47:5 | x [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:53:3:53:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:53:6:53:6 | x [inner post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:75:2:75:10 | access to array [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:75:4:75:6 | val [inner post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:82:2:82:9 | access to array [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:82:4:82:6 | val [inner post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:83:7:83:9 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:97:4:97:6 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:124:4:124:6 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:131:4:131:6 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:138:4:138:6 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:151:5:151:7 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:157:5:157:7 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:158:5:158:7 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:164:5:164:7 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:171:5:171:7 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:178:5:178:7 | val [post update] | PostUpdateNode should not be the target of local flow. | +| clearning.cpp:179:5:179:7 | val [post update] | PostUpdateNode should not be the target of local flow. | | complex.cpp:11:22:11:23 | a_ [post update] | PostUpdateNode should not be the target of local flow. | | complex.cpp:12:22:12:23 | b_ [post update] | PostUpdateNode should not be the target of local flow. | | conflated.cpp:10:3:10:7 | * ... [post update] | PostUpdateNode should not be the target of local flow. | 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 ba007019708..b1acebfde5b 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,17 @@ uniquePostUpdate | aliasing.cpp:77:11:77:11 | definition of w indirection | Node has multiple PostUpdateNodes. | | aliasing.cpp:84:11:84:11 | definition of w indirection | Node has multiple PostUpdateNodes. | | aliasing.cpp:91:11:91:11 | definition of w indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:54:3:54:3 | s indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:61:3:61:3 | s indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:90:3:90:3 | s indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:104:2:104:2 | s indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:111:4:111:4 | s indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:118:2:118:2 | s indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:125:2:125:2 | s indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:132:2:132:2 | s indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:139:4:139:4 | s indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:165:3:165:3 | s indirection | Node has multiple PostUpdateNodes. | +| clearning.cpp:172:3:172:3 | s indirection | Node has multiple PostUpdateNodes. | | complex.cpp:22:3:22:5 | this indirection | Node has multiple PostUpdateNodes. | | complex.cpp:25:7:25:7 | this indirection | Node has multiple PostUpdateNodes. | | complex.cpp:42:10:42:14 | inner indirection | Node has multiple PostUpdateNodes. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index ec21a37dd3f..a90f04df3cf 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -572,6 +572,136 @@ edges | by_reference.cpp:136:8:136:13 | pouter indirection [a] | by_reference.cpp:136:16:136:16 | a | | by_reference.cpp:136:8:136:13 | pouter indirection [a] | by_reference.cpp:136:16:136:16 | a indirection | | by_reference.cpp:136:16:136:16 | a indirection | by_reference.cpp:136:16:136:16 | a | +| clearning.cpp:32:3:32:25 | ... = ... | clearning.cpp:32:6:32:6 | s indirection [post update] [x indirection] | +| clearning.cpp:32:6:32:6 | s indirection [post update] [x indirection] | clearning.cpp:33:5:33:5 | s indirection [x indirection] | +| clearning.cpp:32:10:32:19 | call to user_input | clearning.cpp:32:3:32:25 | ... = ... | +| clearning.cpp:33:5:33:5 | s indirection [x indirection] | clearning.cpp:34:9:34:9 | s indirection [x indirection] | +| clearning.cpp:34:9:34:9 | s indirection [x indirection] | clearning.cpp:34:8:34:11 | * ... | +| clearning.cpp:34:9:34:9 | s indirection [x indirection] | clearning.cpp:34:11:34:11 | x indirection | +| clearning.cpp:34:9:34:9 | s indirection [x indirection] | clearning.cpp:34:11:34:11 | x indirection | +| clearning.cpp:34:11:34:11 | x indirection | clearning.cpp:34:8:34:11 | * ... | +| clearning.cpp:34:11:34:11 | x indirection | clearning.cpp:34:8:34:11 | * ... | +| clearning.cpp:53:3:53:25 | ... = ... | clearning.cpp:53:6:53:6 | s indirection [post update] [x indirection] | +| clearning.cpp:53:6:53:6 | s indirection [post update] [x indirection] | clearning.cpp:54:3:54:3 | s indirection [x indirection] | +| clearning.cpp:53:10:53:19 | call to user_input | clearning.cpp:53:3:53:25 | ... = ... | +| clearning.cpp:54:3:54:3 | s indirection [x indirection] | clearning.cpp:54:3:54:7 | ... ++ indirection | +| clearning.cpp:54:3:54:3 | s indirection [x indirection] | clearning.cpp:54:5:54:5 | x indirection | +| clearning.cpp:54:3:54:3 | s indirection [x indirection] | clearning.cpp:55:8:55:8 | s indirection [x indirection] | +| clearning.cpp:54:3:54:7 | ... ++ indirection | clearning.cpp:54:3:54:7 | ... ++ indirection | +| clearning.cpp:54:3:54:7 | ... ++ indirection | clearning.cpp:54:5:54:5 | s indirection [post update] [x indirection] | +| clearning.cpp:54:5:54:5 | s indirection [post update] [x indirection] | clearning.cpp:55:8:55:8 | s indirection [x indirection] | +| clearning.cpp:54:5:54:5 | x indirection | clearning.cpp:54:3:54:7 | ... ++ indirection | +| clearning.cpp:55:8:55:8 | s indirection [x indirection] | clearning.cpp:55:10:55:10 | x indirection | +| clearning.cpp:55:8:55:8 | s indirection [x indirection] | clearning.cpp:55:10:55:10 | x indirection | +| clearning.cpp:55:10:55:10 | x indirection | clearning.cpp:55:10:55:10 | x indirection | +| clearning.cpp:60:3:60:22 | ... = ... | clearning.cpp:60:7:60:7 | s indirection [post update] [x indirection] | +| clearning.cpp:60:7:60:7 | s indirection [post update] [x indirection] | clearning.cpp:61:3:61:3 | s indirection [x indirection] | +| clearning.cpp:60:11:60:20 | call to user_input | clearning.cpp:60:3:60:22 | ... = ... | +| clearning.cpp:61:3:61:3 | s indirection [x indirection] | clearning.cpp:61:3:61:7 | ... ++ indirection | +| clearning.cpp:61:3:61:3 | s indirection [x indirection] | clearning.cpp:61:5:61:5 | x indirection | +| clearning.cpp:61:3:61:3 | s indirection [x indirection] | clearning.cpp:62:8:62:8 | s indirection [x indirection] | +| clearning.cpp:61:3:61:7 | ... ++ indirection | clearning.cpp:61:3:61:7 | ... ++ indirection | +| clearning.cpp:61:3:61:7 | ... ++ indirection | clearning.cpp:61:5:61:5 | s indirection [post update] [x indirection] | +| clearning.cpp:61:5:61:5 | s indirection [post update] [x indirection] | clearning.cpp:62:8:62:8 | s indirection [x indirection] | +| clearning.cpp:61:5:61:5 | x indirection | clearning.cpp:61:3:61:7 | ... ++ indirection | +| clearning.cpp:62:8:62:8 | s indirection [x indirection] | clearning.cpp:62:10:62:10 | x indirection | +| clearning.cpp:62:8:62:8 | s indirection [x indirection] | clearning.cpp:62:10:62:10 | x indirection | +| clearning.cpp:62:10:62:10 | x indirection | clearning.cpp:62:10:62:10 | x indirection | +| clearning.cpp:74:20:74:22 | argument_source output argument | clearning.cpp:74:20:74:22 | s indirection [post update] [val indirection] | +| clearning.cpp:74:20:74:22 | s indirection [post update] [val indirection] | clearning.cpp:76:8:76:8 | s indirection [val indirection] | +| clearning.cpp:76:8:76:8 | s indirection [val indirection] | clearning.cpp:76:7:76:12 | * ... | +| clearning.cpp:76:8:76:8 | s indirection [val indirection] | clearning.cpp:76:10:76:12 | val indirection | +| clearning.cpp:76:8:76:8 | s indirection [val indirection] | clearning.cpp:76:10:76:12 | val indirection | +| clearning.cpp:76:10:76:12 | val indirection | clearning.cpp:76:7:76:12 | * ... | +| clearning.cpp:76:10:76:12 | val indirection | clearning.cpp:76:7:76:12 | * ... | +| clearning.cpp:81:20:81:22 | argument_source output argument | clearning.cpp:81:20:81:22 | s indirection [post update] [val indirection] | +| clearning.cpp:81:20:81:22 | s indirection [post update] [val indirection] | clearning.cpp:83:13:83:13 | s indirection [val indirection] | +| clearning.cpp:83:5:83:21 | ... = ... indirection | clearning.cpp:83:7:83:9 | s indirection [post update] [val indirection] | +| clearning.cpp:83:7:83:9 | s indirection [post update] [val indirection] | clearning.cpp:84:8:84:8 | s indirection [val indirection] | +| clearning.cpp:83:13:83:13 | s indirection [val indirection] | clearning.cpp:83:13:83:21 | ... + ... indirection | +| clearning.cpp:83:13:83:13 | s indirection [val indirection] | clearning.cpp:83:15:83:17 | val indirection | +| clearning.cpp:83:13:83:21 | ... + ... indirection | clearning.cpp:83:5:83:21 | ... = ... indirection | +| clearning.cpp:83:15:83:17 | val indirection | clearning.cpp:83:5:83:21 | ... = ... indirection | +| clearning.cpp:84:8:84:8 | s indirection [val indirection] | clearning.cpp:84:7:84:12 | * ... | +| clearning.cpp:84:8:84:8 | s indirection [val indirection] | clearning.cpp:84:10:84:12 | val indirection | +| clearning.cpp:84:8:84:8 | s indirection [val indirection] | clearning.cpp:84:10:84:12 | val indirection | +| clearning.cpp:84:10:84:12 | val indirection | clearning.cpp:84:7:84:12 | * ... | +| clearning.cpp:84:10:84:12 | val indirection | clearning.cpp:84:7:84:12 | * ... | +| clearning.cpp:89:20:89:22 | argument_source output argument | clearning.cpp:89:20:89:22 | s indirection [post update] [val indirection] | +| clearning.cpp:89:20:89:22 | s indirection [post update] [val indirection] | clearning.cpp:90:3:90:3 | s indirection [val indirection] | +| clearning.cpp:90:3:90:3 | s indirection [val indirection] | clearning.cpp:90:3:90:9 | ... ++ indirection | +| clearning.cpp:90:3:90:3 | s indirection [val indirection] | clearning.cpp:90:5:90:7 | val indirection | +| clearning.cpp:90:3:90:3 | s indirection [val indirection] | clearning.cpp:91:8:91:8 | s indirection [val indirection] | +| clearning.cpp:90:3:90:9 | ... ++ indirection | clearning.cpp:90:3:90:9 | ... ++ indirection | +| clearning.cpp:90:3:90:9 | ... ++ indirection | clearning.cpp:90:5:90:7 | s indirection [post update] [val indirection] | +| clearning.cpp:90:5:90:7 | s indirection [post update] [val indirection] | clearning.cpp:91:8:91:8 | s indirection [val indirection] | +| clearning.cpp:90:5:90:7 | val indirection | clearning.cpp:90:3:90:9 | ... ++ indirection | +| clearning.cpp:91:8:91:8 | s indirection [val indirection] | clearning.cpp:91:7:91:12 | * ... | +| clearning.cpp:91:8:91:8 | s indirection [val indirection] | clearning.cpp:91:10:91:12 | val indirection | +| clearning.cpp:91:8:91:8 | s indirection [val indirection] | clearning.cpp:91:10:91:12 | val indirection | +| clearning.cpp:91:10:91:12 | val indirection | clearning.cpp:91:7:91:12 | * ... | +| clearning.cpp:91:10:91:12 | val indirection | clearning.cpp:91:7:91:12 | * ... | +| clearning.cpp:96:20:96:22 | argument_source output argument | clearning.cpp:96:20:96:22 | s indirection [post update] [val indirection] | +| clearning.cpp:96:20:96:22 | s indirection [post update] [val indirection] | clearning.cpp:97:10:97:10 | s indirection [val indirection] | +| clearning.cpp:97:2:97:18 | ... = ... indirection | clearning.cpp:97:4:97:6 | s indirection [post update] [val indirection] | +| clearning.cpp:97:4:97:6 | s indirection [post update] [val indirection] | clearning.cpp:98:8:98:8 | s indirection [val indirection] | +| clearning.cpp:97:10:97:10 | s indirection [val indirection] | clearning.cpp:97:10:97:18 | ... + ... indirection | +| clearning.cpp:97:10:97:10 | s indirection [val indirection] | clearning.cpp:97:12:97:14 | val indirection | +| clearning.cpp:97:10:97:18 | ... + ... indirection | clearning.cpp:97:2:97:18 | ... = ... indirection | +| clearning.cpp:97:12:97:14 | val indirection | clearning.cpp:97:2:97:18 | ... = ... indirection | +| clearning.cpp:98:8:98:8 | s indirection [val indirection] | clearning.cpp:98:7:98:12 | * ... | +| clearning.cpp:98:8:98:8 | s indirection [val indirection] | clearning.cpp:98:10:98:12 | val indirection | +| clearning.cpp:98:8:98:8 | s indirection [val indirection] | clearning.cpp:98:10:98:12 | val indirection | +| clearning.cpp:98:10:98:12 | val indirection | clearning.cpp:98:7:98:12 | * ... | +| clearning.cpp:98:10:98:12 | val indirection | clearning.cpp:98:7:98:12 | * ... | +| clearning.cpp:103:20:103:22 | argument_source output argument | clearning.cpp:103:20:103:22 | s indirection [post update] [val indirection] | +| clearning.cpp:103:20:103:22 | s indirection [post update] [val indirection] | clearning.cpp:104:2:104:2 | s indirection [val indirection] | +| clearning.cpp:104:2:104:2 | s indirection [val indirection] | clearning.cpp:104:2:104:8 | ... ++ indirection | +| clearning.cpp:104:2:104:2 | s indirection [val indirection] | clearning.cpp:104:4:104:6 | val indirection | +| clearning.cpp:104:2:104:2 | s indirection [val indirection] | clearning.cpp:105:8:105:8 | s indirection [val indirection] | +| clearning.cpp:104:2:104:8 | ... ++ indirection | clearning.cpp:104:2:104:8 | ... ++ indirection | +| clearning.cpp:104:2:104:8 | ... ++ indirection | clearning.cpp:104:4:104:6 | s indirection [post update] [val indirection] | +| clearning.cpp:104:4:104:6 | s indirection [post update] [val indirection] | clearning.cpp:105:8:105:8 | s indirection [val indirection] | +| clearning.cpp:104:4:104:6 | val indirection | clearning.cpp:104:2:104:8 | ... ++ indirection | +| clearning.cpp:105:8:105:8 | s indirection [val indirection] | clearning.cpp:105:7:105:12 | * ... | +| clearning.cpp:105:8:105:8 | s indirection [val indirection] | clearning.cpp:105:10:105:12 | val indirection | +| clearning.cpp:105:8:105:8 | s indirection [val indirection] | clearning.cpp:105:10:105:12 | val indirection | +| clearning.cpp:105:10:105:12 | val indirection | clearning.cpp:105:7:105:12 | * ... | +| clearning.cpp:105:10:105:12 | val indirection | clearning.cpp:105:7:105:12 | * ... | +| clearning.cpp:110:20:110:22 | argument_source output argument | clearning.cpp:110:20:110:22 | s indirection [post update] [val indirection] | +| clearning.cpp:110:20:110:22 | s indirection [post update] [val indirection] | clearning.cpp:111:4:111:4 | s indirection [val indirection] | +| clearning.cpp:111:2:111:8 | ++ ... indirection | clearning.cpp:111:2:111:8 | ++ ... indirection | +| clearning.cpp:111:2:111:8 | ++ ... indirection | clearning.cpp:111:6:111:8 | s indirection [post update] [val indirection] | +| clearning.cpp:111:4:111:4 | s indirection [val indirection] | clearning.cpp:111:2:111:8 | ++ ... indirection | +| clearning.cpp:111:4:111:4 | s indirection [val indirection] | clearning.cpp:111:6:111:8 | val indirection | +| clearning.cpp:111:4:111:4 | s indirection [val indirection] | clearning.cpp:112:8:112:8 | s indirection [val indirection] | +| clearning.cpp:111:6:111:8 | s indirection [post update] [val indirection] | clearning.cpp:112:8:112:8 | s indirection [val indirection] | +| clearning.cpp:111:6:111:8 | val indirection | clearning.cpp:111:2:111:8 | ++ ... indirection | +| clearning.cpp:112:8:112:8 | s indirection [val indirection] | clearning.cpp:112:7:112:12 | * ... | +| clearning.cpp:112:8:112:8 | s indirection [val indirection] | clearning.cpp:112:10:112:12 | val indirection | +| clearning.cpp:112:8:112:8 | s indirection [val indirection] | clearning.cpp:112:10:112:12 | val indirection | +| clearning.cpp:112:10:112:12 | val indirection | clearning.cpp:112:7:112:12 | * ... | +| clearning.cpp:112:10:112:12 | val indirection | clearning.cpp:112:7:112:12 | * ... | +| clearning.cpp:117:20:117:22 | argument_source output argument | clearning.cpp:117:20:117:22 | s indirection [post update] [val indirection] | +| clearning.cpp:117:20:117:22 | s indirection [post update] [val indirection] | clearning.cpp:118:2:118:2 | s indirection [val indirection] | +| clearning.cpp:118:2:118:2 | s indirection [val indirection] | clearning.cpp:118:2:118:11 | ... += ... indirection | +| clearning.cpp:118:2:118:2 | s indirection [val indirection] | clearning.cpp:118:4:118:6 | val indirection | +| clearning.cpp:118:2:118:2 | s indirection [val indirection] | clearning.cpp:119:8:119:8 | s indirection [val indirection] | +| clearning.cpp:118:2:118:11 | ... += ... indirection | clearning.cpp:118:2:118:11 | ... += ... indirection | +| clearning.cpp:118:2:118:11 | ... += ... indirection | clearning.cpp:118:4:118:6 | s indirection [post update] [val indirection] | +| clearning.cpp:118:4:118:6 | s indirection [post update] [val indirection] | clearning.cpp:119:8:119:8 | s indirection [val indirection] | +| clearning.cpp:118:4:118:6 | val indirection | clearning.cpp:118:2:118:11 | ... += ... indirection | +| clearning.cpp:119:8:119:8 | s indirection [val indirection] | clearning.cpp:119:7:119:12 | * ... | +| clearning.cpp:119:8:119:8 | s indirection [val indirection] | clearning.cpp:119:10:119:12 | val indirection | +| clearning.cpp:119:8:119:8 | s indirection [val indirection] | clearning.cpp:119:10:119:12 | val indirection | +| clearning.cpp:119:10:119:12 | val indirection | clearning.cpp:119:7:119:12 | * ... | +| clearning.cpp:119:10:119:12 | val indirection | clearning.cpp:119:7:119:12 | * ... | +| clearning.cpp:151:3:151:22 | ... = ... | clearning.cpp:151:5:151:7 | s indirection [post update] [val] | +| clearning.cpp:151:5:151:7 | s indirection [post update] [val] | clearning.cpp:152:8:152:8 | s indirection [val] | +| clearning.cpp:151:11:151:20 | call to user_input | clearning.cpp:151:3:151:22 | ... = ... | +| clearning.cpp:152:8:152:8 | s indirection [val] | clearning.cpp:152:10:152:12 | val | +| clearning.cpp:152:8:152:8 | s indirection [val] | clearning.cpp:152:10:152:12 | val indirection | +| clearning.cpp:152:10:152:12 | val indirection | clearning.cpp:152:10:152:12 | val | | complex.cpp:9:7:9:7 | this indirection [a_] | complex.cpp:9:20:9:21 | this indirection [a_] | | complex.cpp:9:20:9:21 | a_ | complex.cpp:9:7:9:7 | a indirection | | complex.cpp:9:20:9:21 | a_ indirection | complex.cpp:9:7:9:7 | a indirection | @@ -861,19 +991,20 @@ edges | struct_init.c:15:8:15:9 | ab indirection [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:15:8:15:9 | ab indirection [a] | struct_init.c:15:12:15:12 | a indirection | | struct_init.c:15:12:15:12 | a indirection | struct_init.c:15:12:15:12 | a | -| struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | struct_init.c:22:8:22:9 | ab indirection [a] | -| struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | struct_init.c:24:10:24:12 | & ... indirection [a] | -| struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | struct_init.c:28:5:28:7 | & ... indirection [a] | +| struct_init.c:20:13:20:14 | definition of ab indirection [a] | struct_init.c:22:8:22:9 | ab indirection [a] | +| struct_init.c:20:13:20:14 | definition of ab indirection [a] | struct_init.c:24:10:24:12 | & ... indirection [a] | +| struct_init.c:20:13:20:14 | definition of ab indirection [a] | struct_init.c:28:5:28:7 | & ... indirection [a] | +| struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | struct_init.c:20:13:20:14 | definition of ab indirection [a] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | call to user_input | | struct_init.c:22:8:22:9 | ab indirection [a] | struct_init.c:22:11:22:11 | a | | struct_init.c:22:8:22:9 | ab indirection [a] | struct_init.c:22:11:22:11 | a indirection | | struct_init.c:22:11:22:11 | a indirection | struct_init.c:22:11:22:11 | a | | struct_init.c:24:10:24:12 | & ... indirection [a] | struct_init.c:14:24:14:25 | ab indirection [a] | -| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:31:8:31:12 | outer indirection [nestedAB, a] | -| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:31:8:31:12 | outer indirection [nestedAB, a] | -| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] | -| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] | +| struct_init.c:26:16:26:20 | definition of outer indirection [nestedAB, a] | struct_init.c:31:8:31:12 | outer indirection [nestedAB, a] | +| struct_init.c:26:16:26:20 | definition of outer indirection [nestedAB, a] | struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] | +| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:26:16:26:20 | definition of outer indirection [nestedAB, a] | +| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:26:16:26:20 | definition of outer indirection [nestedAB, a] | | struct_init.c:26:23:29:3 | definition of outer indirection [post update] [pointerAB indirection, a] | struct_init.c:33:8:33:12 | outer indirection [pointerAB indirection, a] | | struct_init.c:27:5:27:23 | {...} indirection [post update] [a] | struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | | struct_init.c:27:5:27:23 | {...} indirection [post update] [a] | struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | @@ -892,7 +1023,8 @@ edges | struct_init.c:33:25:33:25 | a indirection | struct_init.c:33:25:33:25 | a | | struct_init.c:36:10:36:24 | & ... indirection [a] | struct_init.c:14:24:14:25 | ab indirection [a] | | struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] | struct_init.c:36:10:36:24 | & ... indirection [a] | -| struct_init.c:40:17:40:36 | definition of ab indirection [post update] [a] | struct_init.c:43:5:43:7 | & ... indirection [a] | +| struct_init.c:40:13:40:14 | definition of ab indirection [a] | struct_init.c:43:5:43:7 | & ... indirection [a] | +| struct_init.c:40:17:40:36 | definition of ab indirection [post update] [a] | struct_init.c:40:13:40:14 | definition of ab indirection [a] | | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:40:17:40:36 | definition of ab indirection [post update] [a] | | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:40:20:40:29 | call to user_input | | struct_init.c:41:23:44:3 | definition of outer indirection [post update] [pointerAB indirection, a] | struct_init.c:46:10:46:14 | outer indirection [pointerAB indirection, a] | @@ -1433,6 +1565,114 @@ nodes | by_reference.cpp:136:8:136:13 | pouter indirection [a] | semmle.label | pouter indirection [a] | | by_reference.cpp:136:16:136:16 | a | semmle.label | a | | by_reference.cpp:136:16:136:16 | a indirection | semmle.label | a indirection | +| clearning.cpp:32:3:32:25 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:32:6:32:6 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] | +| clearning.cpp:32:10:32:19 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:33:5:33:5 | s indirection [x indirection] | semmle.label | s indirection [x indirection] | +| clearning.cpp:34:8:34:11 | * ... | semmle.label | * ... | +| clearning.cpp:34:9:34:9 | s indirection [x indirection] | semmle.label | s indirection [x indirection] | +| clearning.cpp:34:11:34:11 | x indirection | semmle.label | x indirection | +| clearning.cpp:34:11:34:11 | x indirection | semmle.label | x indirection | +| clearning.cpp:53:3:53:25 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:53:6:53:6 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] | +| clearning.cpp:53:10:53:19 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:54:3:54:3 | s indirection [x indirection] | semmle.label | s indirection [x indirection] | +| clearning.cpp:54:3:54:7 | ... ++ indirection | semmle.label | ... ++ indirection | +| clearning.cpp:54:3:54:7 | ... ++ indirection | semmle.label | ... ++ indirection | +| clearning.cpp:54:5:54:5 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] | +| clearning.cpp:54:5:54:5 | x indirection | semmle.label | x indirection | +| clearning.cpp:55:8:55:8 | s indirection [x indirection] | semmle.label | s indirection [x indirection] | +| clearning.cpp:55:10:55:10 | x indirection | semmle.label | x indirection | +| clearning.cpp:55:10:55:10 | x indirection | semmle.label | x indirection | +| clearning.cpp:60:3:60:22 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:60:7:60:7 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] | +| clearning.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:61:3:61:3 | s indirection [x indirection] | semmle.label | s indirection [x indirection] | +| clearning.cpp:61:3:61:7 | ... ++ indirection | semmle.label | ... ++ indirection | +| clearning.cpp:61:3:61:7 | ... ++ indirection | semmle.label | ... ++ indirection | +| clearning.cpp:61:5:61:5 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] | +| clearning.cpp:61:5:61:5 | x indirection | semmle.label | x indirection | +| clearning.cpp:62:8:62:8 | s indirection [x indirection] | semmle.label | s indirection [x indirection] | +| clearning.cpp:62:10:62:10 | x indirection | semmle.label | x indirection | +| clearning.cpp:62:10:62:10 | x indirection | semmle.label | x indirection | +| clearning.cpp:74:20:74:22 | argument_source output argument | semmle.label | argument_source output argument | +| clearning.cpp:74:20:74:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:76:7:76:12 | * ... | semmle.label | * ... | +| clearning.cpp:76:8:76:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:76:10:76:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:76:10:76:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:81:20:81:22 | argument_source output argument | semmle.label | argument_source output argument | +| clearning.cpp:81:20:81:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:83:5:83:21 | ... = ... indirection | semmle.label | ... = ... indirection | +| clearning.cpp:83:7:83:9 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:83:13:83:13 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:83:13:83:21 | ... + ... indirection | semmle.label | ... + ... indirection | +| clearning.cpp:83:15:83:17 | val indirection | semmle.label | val indirection | +| clearning.cpp:84:7:84:12 | * ... | semmle.label | * ... | +| clearning.cpp:84:8:84:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:84:10:84:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:84:10:84:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:89:20:89:22 | argument_source output argument | semmle.label | argument_source output argument | +| clearning.cpp:89:20:89:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:90:3:90:3 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:90:3:90:9 | ... ++ indirection | semmle.label | ... ++ indirection | +| clearning.cpp:90:3:90:9 | ... ++ indirection | semmle.label | ... ++ indirection | +| clearning.cpp:90:5:90:7 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:90:5:90:7 | val indirection | semmle.label | val indirection | +| clearning.cpp:91:7:91:12 | * ... | semmle.label | * ... | +| clearning.cpp:91:8:91:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:91:10:91:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:91:10:91:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:96:20:96:22 | argument_source output argument | semmle.label | argument_source output argument | +| clearning.cpp:96:20:96:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:97:2:97:18 | ... = ... indirection | semmle.label | ... = ... indirection | +| clearning.cpp:97:4:97:6 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:97:10:97:10 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:97:10:97:18 | ... + ... indirection | semmle.label | ... + ... indirection | +| clearning.cpp:97:12:97:14 | val indirection | semmle.label | val indirection | +| clearning.cpp:98:7:98:12 | * ... | semmle.label | * ... | +| clearning.cpp:98:8:98:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:98:10:98:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:98:10:98:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:103:20:103:22 | argument_source output argument | semmle.label | argument_source output argument | +| clearning.cpp:103:20:103:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:104:2:104:2 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:104:2:104:8 | ... ++ indirection | semmle.label | ... ++ indirection | +| clearning.cpp:104:2:104:8 | ... ++ indirection | semmle.label | ... ++ indirection | +| clearning.cpp:104:4:104:6 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:104:4:104:6 | val indirection | semmle.label | val indirection | +| clearning.cpp:105:7:105:12 | * ... | semmle.label | * ... | +| clearning.cpp:105:8:105:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:105:10:105:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:105:10:105:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:110:20:110:22 | argument_source output argument | semmle.label | argument_source output argument | +| clearning.cpp:110:20:110:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:111:2:111:8 | ++ ... indirection | semmle.label | ++ ... indirection | +| clearning.cpp:111:2:111:8 | ++ ... indirection | semmle.label | ++ ... indirection | +| clearning.cpp:111:4:111:4 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:111:6:111:8 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:111:6:111:8 | val indirection | semmle.label | val indirection | +| clearning.cpp:112:7:112:12 | * ... | semmle.label | * ... | +| clearning.cpp:112:8:112:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:112:10:112:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:112:10:112:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:117:20:117:22 | argument_source output argument | semmle.label | argument_source output argument | +| clearning.cpp:117:20:117:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:118:2:118:2 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:118:2:118:11 | ... += ... indirection | semmle.label | ... += ... indirection | +| clearning.cpp:118:2:118:11 | ... += ... indirection | semmle.label | ... += ... indirection | +| clearning.cpp:118:4:118:6 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] | +| clearning.cpp:118:4:118:6 | val indirection | semmle.label | val indirection | +| clearning.cpp:119:7:119:12 | * ... | semmle.label | * ... | +| clearning.cpp:119:8:119:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] | +| clearning.cpp:119:10:119:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:119:10:119:12 | val indirection | semmle.label | val indirection | +| clearning.cpp:151:3:151:22 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:151:5:151:7 | s indirection [post update] [val] | semmle.label | s indirection [post update] [val] | +| clearning.cpp:151:11:151:20 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:152:8:152:8 | s indirection [val] | semmle.label | s indirection [val] | +| clearning.cpp:152:10:152:12 | val | semmle.label | val | +| clearning.cpp:152:10:152:12 | val indirection | semmle.label | val indirection | | complex.cpp:9:7:9:7 | a indirection | semmle.label | a indirection | | complex.cpp:9:7:9:7 | this indirection [a_] | semmle.label | this indirection [a_] | | complex.cpp:9:20:9:21 | a_ | semmle.label | a_ | @@ -1699,6 +1939,7 @@ nodes | struct_init.c:15:8:15:9 | ab indirection [a] | semmle.label | ab indirection [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | | struct_init.c:15:12:15:12 | a indirection | semmle.label | a indirection | +| struct_init.c:20:13:20:14 | definition of ab indirection [a] | semmle.label | definition of ab indirection [a] | | struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | semmle.label | definition of ab indirection [post update] [a] | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | @@ -1706,6 +1947,7 @@ nodes | struct_init.c:22:11:22:11 | a | semmle.label | a | | struct_init.c:22:11:22:11 | a indirection | semmle.label | a indirection | | struct_init.c:24:10:24:12 | & ... indirection [a] | semmle.label | & ... indirection [a] | +| struct_init.c:26:16:26:20 | definition of outer indirection [nestedAB, a] | semmle.label | definition of outer indirection [nestedAB, a] | | struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | semmle.label | definition of outer indirection [post update] [nestedAB, a] | | struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | semmle.label | definition of outer indirection [post update] [nestedAB, a] | | struct_init.c:26:23:29:3 | definition of outer indirection [post update] [pointerAB indirection, a] | semmle.label | definition of outer indirection [post update] [pointerAB indirection, a] | @@ -1724,6 +1966,7 @@ nodes | struct_init.c:33:25:33:25 | a indirection | semmle.label | a indirection | | struct_init.c:36:10:36:24 | & ... indirection [a] | semmle.label | & ... indirection [a] | | struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] | semmle.label | outer indirection [nestedAB, a] | +| struct_init.c:40:13:40:14 | definition of ab indirection [a] | semmle.label | definition of ab indirection [a] | | struct_init.c:40:17:40:36 | definition of ab indirection [post update] [a] | semmle.label | definition of ab indirection [post update] [a] | | struct_init.c:40:20:40:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:40:20:40:29 | call to user_input | semmle.label | call to user_input | @@ -1883,6 +2126,17 @@ subpaths | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | +| clearning.cpp:34:8:34:11 | * ... | clearning.cpp:32:10:32:19 | call to user_input | clearning.cpp:34:8:34:11 | * ... | * ... flows from $@ | clearning.cpp:32:10:32:19 | call to user_input | call to user_input | +| clearning.cpp:55:10:55:10 | x indirection | clearning.cpp:53:10:53:19 | call to user_input | clearning.cpp:55:10:55:10 | x indirection | x indirection flows from $@ | clearning.cpp:53:10:53:19 | call to user_input | call to user_input | +| clearning.cpp:62:10:62:10 | x indirection | clearning.cpp:60:11:60:20 | call to user_input | clearning.cpp:62:10:62:10 | x indirection | x indirection flows from $@ | clearning.cpp:60:11:60:20 | call to user_input | call to user_input | +| clearning.cpp:76:7:76:12 | * ... | clearning.cpp:74:20:74:22 | argument_source output argument | clearning.cpp:76:7:76:12 | * ... | * ... flows from $@ | clearning.cpp:74:20:74:22 | argument_source output argument | argument_source output argument | +| clearning.cpp:84:7:84:12 | * ... | clearning.cpp:81:20:81:22 | argument_source output argument | clearning.cpp:84:7:84:12 | * ... | * ... flows from $@ | clearning.cpp:81:20:81:22 | argument_source output argument | argument_source output argument | +| clearning.cpp:91:7:91:12 | * ... | clearning.cpp:89:20:89:22 | argument_source output argument | clearning.cpp:91:7:91:12 | * ... | * ... flows from $@ | clearning.cpp:89:20:89:22 | argument_source output argument | argument_source output argument | +| clearning.cpp:98:7:98:12 | * ... | clearning.cpp:96:20:96:22 | argument_source output argument | clearning.cpp:98:7:98:12 | * ... | * ... flows from $@ | clearning.cpp:96:20:96:22 | argument_source output argument | argument_source output argument | +| clearning.cpp:105:7:105:12 | * ... | clearning.cpp:103:20:103:22 | argument_source output argument | clearning.cpp:105:7:105:12 | * ... | * ... flows from $@ | clearning.cpp:103:20:103:22 | argument_source output argument | argument_source output argument | +| clearning.cpp:112:7:112:12 | * ... | clearning.cpp:110:20:110:22 | argument_source output argument | clearning.cpp:112:7:112:12 | * ... | * ... flows from $@ | clearning.cpp:110:20:110:22 | argument_source output argument | argument_source output argument | +| clearning.cpp:119:7:119:12 | * ... | clearning.cpp:117:20:117:22 | argument_source output argument | clearning.cpp:119:7:119:12 | * ... | * ... flows from $@ | clearning.cpp:117:20:117:22 | argument_source output argument | argument_source output argument | +| clearning.cpp:152:10:152:12 | val | clearning.cpp:151:11:151:20 | call to user_input | clearning.cpp:152:10:152:12 | val | val flows from $@ | clearning.cpp:151:11:151:20 | call to user_input | call to user_input | | complex.cpp:42:18:42:18 | call to a | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:53:19:53:28 | call to user_input | call to user_input | | complex.cpp:42:18:42:18 | call to a | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:55:19:55:28 | call to user_input | call to user_input | | complex.cpp:43:18:43:18 | call to b | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:43:18:43:18 | call to b | call to b flows from $@ | complex.cpp:54:19:54:28 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 6749e278fba..ad76accce67 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -167,6 +167,66 @@ | by_reference.cpp:88:9:88:9 | a | AST only | | by_reference.cpp:92:3:92:5 | * ... | AST only | | by_reference.cpp:96:3:96:4 | pa | AST only | +| clearning.cpp:18:7:18:7 | s | IR only | +| clearning.cpp:19:3:19:6 | * ... | AST only | +| clearning.cpp:20:12:20:12 | s | IR only | +| clearning.cpp:25:7:25:7 | s | IR only | +| clearning.cpp:26:7:26:7 | s | IR only | +| clearning.cpp:27:12:27:12 | s | IR only | +| clearning.cpp:32:3:32:6 | * ... | AST only | +| clearning.cpp:33:7:33:7 | s | IR only | +| clearning.cpp:34:8:34:11 | * ... | IR only | +| clearning.cpp:34:11:34:11 | s | IR only | +| clearning.cpp:39:3:39:6 | * ... | AST only | +| clearning.cpp:40:5:40:5 | x | AST only | +| clearning.cpp:41:8:41:11 | * ... | IR only | +| clearning.cpp:41:11:41:11 | s | IR only | +| clearning.cpp:46:7:46:7 | s | IR only | +| clearning.cpp:47:5:47:5 | x | AST only | +| clearning.cpp:48:8:48:11 | * ... | IR only | +| clearning.cpp:48:11:48:11 | s | IR only | +| clearning.cpp:53:3:53:6 | * ... | AST only | +| clearning.cpp:54:5:54:5 | x | AST only | +| clearning.cpp:60:7:60:7 | s | IR only | +| clearning.cpp:61:5:61:5 | x | AST only | +| clearning.cpp:75:2:75:10 | access to array | AST only | +| clearning.cpp:76:10:76:12 | s | IR only | +| clearning.cpp:82:2:82:9 | access to array | AST only | +| clearning.cpp:83:7:83:9 | val | AST only | +| clearning.cpp:83:15:83:17 | s | IR only | +| clearning.cpp:84:10:84:12 | s | IR only | +| clearning.cpp:90:5:90:7 | val | AST only | +| clearning.cpp:91:10:91:12 | s | IR only | +| clearning.cpp:97:4:97:6 | val | AST only | +| clearning.cpp:97:12:97:14 | s | IR only | +| clearning.cpp:98:10:98:12 | s | IR only | +| clearning.cpp:104:4:104:6 | val | AST only | +| clearning.cpp:105:10:105:12 | s | IR only | +| clearning.cpp:111:6:111:8 | val | AST only | +| clearning.cpp:112:10:112:12 | s | IR only | +| clearning.cpp:118:4:118:6 | val | AST only | +| clearning.cpp:119:10:119:12 | s | IR only | +| clearning.cpp:124:4:124:6 | val | AST only | +| clearning.cpp:125:4:125:6 | val | AST only | +| clearning.cpp:131:4:131:6 | val | AST only | +| clearning.cpp:132:4:132:6 | val | AST only | +| clearning.cpp:138:4:138:6 | val | AST only | +| clearning.cpp:139:6:139:8 | val | AST only | +| clearning.cpp:151:5:151:7 | val | AST only | +| clearning.cpp:152:10:152:12 | s | IR only | +| clearning.cpp:157:5:157:7 | val | AST only | +| clearning.cpp:158:5:158:7 | val | AST only | +| clearning.cpp:159:10:159:12 | s | IR only | +| clearning.cpp:164:5:164:7 | val | AST only | +| clearning.cpp:165:5:165:7 | val | AST only | +| clearning.cpp:166:10:166:12 | s | IR only | +| clearning.cpp:171:5:171:7 | val | AST only | +| clearning.cpp:172:5:172:7 | val | AST only | +| clearning.cpp:173:10:173:12 | s | IR only | +| clearning.cpp:178:5:178:7 | val | AST only | +| clearning.cpp:179:5:179:7 | val | AST only | +| clearning.cpp:179:13:179:15 | s | IR only | +| clearning.cpp:180:10:180:12 | s | IR only | | complex.cpp:9:20:9:21 | this | IR only | | complex.cpp:10:20:10:21 | this | IR only | | complex.cpp:11:22:11:23 | a_ | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index 1818cea24bb..823997fd7d3 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -408,6 +408,90 @@ | by_reference.cpp:135:27:135:27 | a | | by_reference.cpp:136:8:136:13 | pouter | | by_reference.cpp:136:16:136:16 | a | +| clearning.cpp:18:5:18:5 | s | +| clearning.cpp:19:4:19:4 | s | +| clearning.cpp:20:10:20:10 | s | +| clearning.cpp:25:5:25:5 | s | +| clearning.cpp:26:5:26:5 | s | +| clearning.cpp:27:10:27:10 | s | +| clearning.cpp:32:4:32:4 | s | +| clearning.cpp:33:5:33:5 | s | +| clearning.cpp:34:8:34:11 | * ... | +| clearning.cpp:34:9:34:9 | s | +| clearning.cpp:39:4:39:4 | s | +| clearning.cpp:40:3:40:3 | s | +| clearning.cpp:41:8:41:11 | * ... | +| clearning.cpp:41:9:41:9 | s | +| clearning.cpp:46:5:46:5 | s | +| clearning.cpp:47:3:47:3 | s | +| clearning.cpp:48:8:48:11 | * ... | +| clearning.cpp:48:9:48:9 | s | +| clearning.cpp:53:4:53:4 | s | +| clearning.cpp:54:3:54:3 | s | +| clearning.cpp:55:8:55:8 | s | +| clearning.cpp:55:10:55:10 | x | +| clearning.cpp:60:5:60:5 | s | +| clearning.cpp:61:3:61:3 | s | +| clearning.cpp:62:8:62:8 | s | +| clearning.cpp:62:10:62:10 | x | +| clearning.cpp:74:18:74:18 | s | +| clearning.cpp:74:20:74:22 | val | +| clearning.cpp:75:2:75:2 | s | +| clearning.cpp:76:8:76:8 | s | +| clearning.cpp:81:18:81:18 | s | +| clearning.cpp:81:20:81:22 | val | +| clearning.cpp:82:2:82:2 | s | +| clearning.cpp:83:5:83:5 | s | +| clearning.cpp:83:13:83:13 | s | +| clearning.cpp:84:8:84:8 | s | +| clearning.cpp:89:18:89:18 | s | +| clearning.cpp:89:20:89:22 | val | +| clearning.cpp:90:3:90:3 | s | +| clearning.cpp:91:8:91:8 | s | +| clearning.cpp:96:18:96:18 | s | +| clearning.cpp:96:20:96:22 | val | +| clearning.cpp:97:2:97:2 | s | +| clearning.cpp:97:10:97:10 | s | +| clearning.cpp:98:8:98:8 | s | +| clearning.cpp:103:18:103:18 | s | +| clearning.cpp:103:20:103:22 | val | +| clearning.cpp:104:2:104:2 | s | +| clearning.cpp:105:8:105:8 | s | +| clearning.cpp:110:18:110:18 | s | +| clearning.cpp:110:20:110:22 | val | +| clearning.cpp:111:4:111:4 | s | +| clearning.cpp:112:8:112:8 | s | +| clearning.cpp:117:18:117:18 | s | +| clearning.cpp:117:20:117:22 | val | +| clearning.cpp:118:2:118:2 | s | +| clearning.cpp:119:8:119:8 | s | +| clearning.cpp:124:2:124:2 | s | +| clearning.cpp:125:2:125:2 | s | +| clearning.cpp:126:7:126:7 | s | +| clearning.cpp:126:9:126:11 | val | +| clearning.cpp:131:2:131:2 | s | +| clearning.cpp:132:2:132:2 | s | +| clearning.cpp:133:7:133:7 | s | +| clearning.cpp:133:9:133:11 | val | +| clearning.cpp:138:2:138:2 | s | +| clearning.cpp:139:4:139:4 | s | +| clearning.cpp:140:7:140:7 | s | +| clearning.cpp:140:9:140:11 | val | +| clearning.cpp:151:3:151:3 | s | +| clearning.cpp:152:8:152:8 | s | +| clearning.cpp:157:3:157:3 | s | +| clearning.cpp:158:3:158:3 | s | +| clearning.cpp:159:8:159:8 | s | +| clearning.cpp:164:3:164:3 | s | +| clearning.cpp:165:3:165:3 | s | +| clearning.cpp:166:8:166:8 | s | +| clearning.cpp:171:3:171:3 | s | +| clearning.cpp:172:3:172:3 | s | +| clearning.cpp:173:8:173:8 | s | +| clearning.cpp:178:3:178:3 | s | +| clearning.cpp:179:3:179:3 | s | +| clearning.cpp:179:11:179:11 | s | +| clearning.cpp:180:8:180:8 | s | | complex.cpp:9:20:9:21 | this | | complex.cpp:10:20:10:21 | this | | complex.cpp:11:22:11:23 | this | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected index 373e357142a..c37eca67c75 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -348,6 +348,92 @@ | by_reference.cpp:135:27:135:27 | a | | by_reference.cpp:136:8:136:13 | pouter | | by_reference.cpp:136:16:136:16 | a | +| clearning.cpp:19:3:19:6 | * ... | +| clearning.cpp:19:4:19:4 | s | +| clearning.cpp:32:3:32:6 | * ... | +| clearning.cpp:32:4:32:4 | s | +| clearning.cpp:39:3:39:6 | * ... | +| clearning.cpp:39:4:39:4 | s | +| clearning.cpp:40:3:40:3 | s | +| clearning.cpp:40:5:40:5 | x | +| clearning.cpp:47:3:47:3 | s | +| clearning.cpp:47:5:47:5 | x | +| clearning.cpp:53:3:53:6 | * ... | +| clearning.cpp:53:4:53:4 | s | +| clearning.cpp:54:3:54:3 | s | +| clearning.cpp:54:5:54:5 | x | +| clearning.cpp:55:8:55:8 | s | +| clearning.cpp:55:10:55:10 | x | +| clearning.cpp:61:3:61:3 | s | +| clearning.cpp:61:5:61:5 | x | +| clearning.cpp:62:8:62:8 | s | +| clearning.cpp:62:10:62:10 | x | +| clearning.cpp:74:18:74:18 | s | +| clearning.cpp:74:20:74:22 | val | +| clearning.cpp:75:2:75:2 | s | +| clearning.cpp:75:2:75:10 | access to array | +| clearning.cpp:81:18:81:18 | s | +| clearning.cpp:81:20:81:22 | val | +| clearning.cpp:82:2:82:2 | s | +| clearning.cpp:82:2:82:9 | access to array | +| clearning.cpp:83:5:83:5 | s | +| clearning.cpp:83:7:83:9 | val | +| clearning.cpp:89:18:89:18 | s | +| clearning.cpp:89:20:89:22 | val | +| clearning.cpp:90:3:90:3 | s | +| clearning.cpp:90:5:90:7 | val | +| clearning.cpp:96:18:96:18 | s | +| clearning.cpp:96:20:96:22 | val | +| clearning.cpp:97:2:97:2 | s | +| clearning.cpp:97:4:97:6 | val | +| clearning.cpp:103:18:103:18 | s | +| clearning.cpp:103:20:103:22 | val | +| clearning.cpp:104:2:104:2 | s | +| clearning.cpp:104:4:104:6 | val | +| clearning.cpp:110:18:110:18 | s | +| clearning.cpp:110:20:110:22 | val | +| clearning.cpp:111:4:111:4 | s | +| clearning.cpp:111:6:111:8 | val | +| clearning.cpp:117:18:117:18 | s | +| clearning.cpp:117:20:117:22 | val | +| clearning.cpp:118:2:118:2 | s | +| clearning.cpp:118:4:118:6 | val | +| clearning.cpp:124:2:124:2 | s | +| clearning.cpp:124:4:124:6 | val | +| clearning.cpp:125:2:125:2 | s | +| clearning.cpp:125:4:125:6 | val | +| clearning.cpp:126:7:126:7 | s | +| clearning.cpp:126:9:126:11 | val | +| clearning.cpp:131:2:131:2 | s | +| clearning.cpp:131:4:131:6 | val | +| clearning.cpp:132:2:132:2 | s | +| clearning.cpp:132:4:132:6 | val | +| clearning.cpp:133:7:133:7 | s | +| clearning.cpp:133:9:133:11 | val | +| clearning.cpp:138:2:138:2 | s | +| clearning.cpp:138:4:138:6 | val | +| clearning.cpp:139:4:139:4 | s | +| clearning.cpp:139:6:139:8 | val | +| clearning.cpp:140:7:140:7 | s | +| clearning.cpp:140:9:140:11 | val | +| clearning.cpp:151:3:151:3 | s | +| clearning.cpp:151:5:151:7 | val | +| clearning.cpp:157:3:157:3 | s | +| clearning.cpp:157:5:157:7 | val | +| clearning.cpp:158:3:158:3 | s | +| clearning.cpp:158:5:158:7 | val | +| clearning.cpp:164:3:164:3 | s | +| clearning.cpp:164:5:164:7 | val | +| clearning.cpp:165:3:165:3 | s | +| clearning.cpp:165:5:165:7 | val | +| clearning.cpp:171:3:171:3 | s | +| clearning.cpp:171:5:171:7 | val | +| clearning.cpp:172:3:172:3 | s | +| clearning.cpp:172:5:172:7 | val | +| clearning.cpp:178:3:178:3 | s | +| clearning.cpp:178:5:178:7 | val | +| clearning.cpp:179:3:179:3 | s | +| clearning.cpp:179:5:179:7 | val | | complex.cpp:11:22:11:23 | a_ | | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | b_ | diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected index 9eef2881545..00a5f1a3f28 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -448,6 +448,42 @@ edges | by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] | | by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a | | by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a | +| clearning.cpp:53:4:53:4 | s [post update] [x] | clearning.cpp:55:8:55:8 | s [x] | +| clearning.cpp:53:6:53:6 | x [inner post update] | clearning.cpp:53:4:53:4 | s [post update] [x] | +| clearning.cpp:53:10:53:19 | call to user_input | clearning.cpp:53:6:53:6 | x [inner post update] | +| clearning.cpp:55:8:55:8 | s [x] | clearning.cpp:55:10:55:10 | x | +| clearning.cpp:124:2:124:2 | s [post update] [val] | clearning.cpp:126:7:126:7 | s [val] | +| clearning.cpp:124:2:124:25 | ... = ... | clearning.cpp:124:2:124:2 | s [post update] [val] | +| clearning.cpp:124:10:124:19 | call to user_input | clearning.cpp:124:2:124:25 | ... = ... | +| clearning.cpp:126:7:126:7 | s [val] | clearning.cpp:126:9:126:11 | val | +| clearning.cpp:131:2:131:2 | s [post update] [val] | clearning.cpp:133:7:133:7 | s [val] | +| clearning.cpp:131:2:131:25 | ... = ... | clearning.cpp:131:2:131:2 | s [post update] [val] | +| clearning.cpp:131:10:131:19 | call to user_input | clearning.cpp:131:2:131:25 | ... = ... | +| clearning.cpp:133:7:133:7 | s [val] | clearning.cpp:133:9:133:11 | val | +| clearning.cpp:138:2:138:2 | s [post update] [val] | clearning.cpp:140:7:140:7 | s [val] | +| clearning.cpp:138:2:138:25 | ... = ... | clearning.cpp:138:2:138:2 | s [post update] [val] | +| clearning.cpp:138:10:138:19 | call to user_input | clearning.cpp:138:2:138:25 | ... = ... | +| clearning.cpp:140:7:140:7 | s [val] | clearning.cpp:140:9:140:11 | val | +| clearning.cpp:151:3:151:3 | s [post update] [val] | clearning.cpp:152:8:152:8 | s [val] | +| clearning.cpp:151:3:151:22 | ... = ... | clearning.cpp:151:3:151:3 | s [post update] [val] | +| clearning.cpp:151:11:151:20 | call to user_input | clearning.cpp:151:3:151:22 | ... = ... | +| clearning.cpp:152:8:152:8 | s [val] | clearning.cpp:152:10:152:12 | val | +| clearning.cpp:157:3:157:3 | s [post update] [val] | clearning.cpp:159:8:159:8 | s [val] | +| clearning.cpp:157:3:157:22 | ... = ... | clearning.cpp:157:3:157:3 | s [post update] [val] | +| clearning.cpp:157:11:157:20 | call to user_input | clearning.cpp:157:3:157:22 | ... = ... | +| clearning.cpp:159:8:159:8 | s [val] | clearning.cpp:159:10:159:12 | val | +| clearning.cpp:164:3:164:3 | s [post update] [val] | clearning.cpp:166:8:166:8 | s [val] | +| clearning.cpp:164:3:164:22 | ... = ... | clearning.cpp:164:3:164:3 | s [post update] [val] | +| clearning.cpp:164:11:164:20 | call to user_input | clearning.cpp:164:3:164:22 | ... = ... | +| clearning.cpp:166:8:166:8 | s [val] | clearning.cpp:166:10:166:12 | val | +| clearning.cpp:171:3:171:3 | s [post update] [val] | clearning.cpp:173:8:173:8 | s [val] | +| clearning.cpp:171:3:171:22 | ... = ... | clearning.cpp:171:3:171:3 | s [post update] [val] | +| clearning.cpp:171:11:171:20 | call to user_input | clearning.cpp:171:3:171:22 | ... = ... | +| clearning.cpp:173:8:173:8 | s [val] | clearning.cpp:173:10:173:12 | val | +| clearning.cpp:178:3:178:3 | s [post update] [val] | clearning.cpp:180:8:180:8 | s [val] | +| clearning.cpp:178:3:178:22 | ... = ... | clearning.cpp:178:3:178:3 | s [post update] [val] | +| clearning.cpp:178:11:178:20 | call to user_input | clearning.cpp:178:3:178:22 | ... = ... | +| clearning.cpp:180:8:180:8 | s [val] | clearning.cpp:180:10:180:12 | val | | complex.cpp:9:7:9:7 | this [a_] | complex.cpp:9:20:9:21 | this [a_] | | complex.cpp:9:20:9:21 | this [a_] | complex.cpp:9:20:9:21 | a_ | | complex.cpp:10:7:10:7 | this [b_] | complex.cpp:10:20:10:21 | this [b_] | @@ -1155,6 +1191,51 @@ nodes | by_reference.cpp:135:27:135:27 | a | semmle.label | a | | by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] | | by_reference.cpp:136:16:136:16 | a | semmle.label | a | +| clearning.cpp:53:4:53:4 | s [post update] [x] | semmle.label | s [post update] [x] | +| clearning.cpp:53:6:53:6 | x [inner post update] | semmle.label | x [inner post update] | +| clearning.cpp:53:10:53:19 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:55:8:55:8 | s [x] | semmle.label | s [x] | +| clearning.cpp:55:10:55:10 | x | semmle.label | x | +| clearning.cpp:124:2:124:2 | s [post update] [val] | semmle.label | s [post update] [val] | +| clearning.cpp:124:2:124:25 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:124:10:124:19 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:126:7:126:7 | s [val] | semmle.label | s [val] | +| clearning.cpp:126:9:126:11 | val | semmle.label | val | +| clearning.cpp:131:2:131:2 | s [post update] [val] | semmle.label | s [post update] [val] | +| clearning.cpp:131:2:131:25 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:131:10:131:19 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:133:7:133:7 | s [val] | semmle.label | s [val] | +| clearning.cpp:133:9:133:11 | val | semmle.label | val | +| clearning.cpp:138:2:138:2 | s [post update] [val] | semmle.label | s [post update] [val] | +| clearning.cpp:138:2:138:25 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:138:10:138:19 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:140:7:140:7 | s [val] | semmle.label | s [val] | +| clearning.cpp:140:9:140:11 | val | semmle.label | val | +| clearning.cpp:151:3:151:3 | s [post update] [val] | semmle.label | s [post update] [val] | +| clearning.cpp:151:3:151:22 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:151:11:151:20 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:152:8:152:8 | s [val] | semmle.label | s [val] | +| clearning.cpp:152:10:152:12 | val | semmle.label | val | +| clearning.cpp:157:3:157:3 | s [post update] [val] | semmle.label | s [post update] [val] | +| clearning.cpp:157:3:157:22 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:157:11:157:20 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:159:8:159:8 | s [val] | semmle.label | s [val] | +| clearning.cpp:159:10:159:12 | val | semmle.label | val | +| clearning.cpp:164:3:164:3 | s [post update] [val] | semmle.label | s [post update] [val] | +| clearning.cpp:164:3:164:22 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:164:11:164:20 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:166:8:166:8 | s [val] | semmle.label | s [val] | +| clearning.cpp:166:10:166:12 | val | semmle.label | val | +| clearning.cpp:171:3:171:3 | s [post update] [val] | semmle.label | s [post update] [val] | +| clearning.cpp:171:3:171:22 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:171:11:171:20 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:173:8:173:8 | s [val] | semmle.label | s [val] | +| clearning.cpp:173:10:173:12 | val | semmle.label | val | +| clearning.cpp:178:3:178:3 | s [post update] [val] | semmle.label | s [post update] [val] | +| clearning.cpp:178:3:178:22 | ... = ... | semmle.label | ... = ... | +| clearning.cpp:178:11:178:20 | call to user_input | semmle.label | call to user_input | +| clearning.cpp:180:8:180:8 | s [val] | semmle.label | s [val] | +| clearning.cpp:180:10:180:12 | val | semmle.label | val | | complex.cpp:9:7:9:7 | this [a_] | semmle.label | this [a_] | | complex.cpp:9:20:9:21 | a_ | semmle.label | a_ | | complex.cpp:9:20:9:21 | this [a_] | semmle.label | this [a_] | @@ -1551,6 +1632,15 @@ subpaths | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | +| clearning.cpp:55:10:55:10 | x | clearning.cpp:53:10:53:19 | call to user_input | clearning.cpp:55:10:55:10 | x | x flows from $@ | clearning.cpp:53:10:53:19 | call to user_input | call to user_input | +| clearning.cpp:126:9:126:11 | val | clearning.cpp:124:10:124:19 | call to user_input | clearning.cpp:126:9:126:11 | val | val flows from $@ | clearning.cpp:124:10:124:19 | call to user_input | call to user_input | +| clearning.cpp:133:9:133:11 | val | clearning.cpp:131:10:131:19 | call to user_input | clearning.cpp:133:9:133:11 | val | val flows from $@ | clearning.cpp:131:10:131:19 | call to user_input | call to user_input | +| clearning.cpp:140:9:140:11 | val | clearning.cpp:138:10:138:19 | call to user_input | clearning.cpp:140:9:140:11 | val | val flows from $@ | clearning.cpp:138:10:138:19 | call to user_input | call to user_input | +| clearning.cpp:152:10:152:12 | val | clearning.cpp:151:11:151:20 | call to user_input | clearning.cpp:152:10:152:12 | val | val flows from $@ | clearning.cpp:151:11:151:20 | call to user_input | call to user_input | +| clearning.cpp:159:10:159:12 | val | clearning.cpp:157:11:157:20 | call to user_input | clearning.cpp:159:10:159:12 | val | val flows from $@ | clearning.cpp:157:11:157:20 | call to user_input | call to user_input | +| clearning.cpp:166:10:166:12 | val | clearning.cpp:164:11:164:20 | call to user_input | clearning.cpp:166:10:166:12 | val | val flows from $@ | clearning.cpp:164:11:164:20 | call to user_input | call to user_input | +| clearning.cpp:173:10:173:12 | val | clearning.cpp:171:11:171:20 | call to user_input | clearning.cpp:173:10:173:12 | val | val flows from $@ | clearning.cpp:171:11:171:20 | call to user_input | call to user_input | +| clearning.cpp:180:10:180:12 | val | clearning.cpp:178:11:178:20 | call to user_input | clearning.cpp:180:10:180:12 | val | val flows from $@ | clearning.cpp:178:11:178:20 | call to user_input | call to user_input | | complex.cpp:42:18:42:18 | call to a | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:53:19:53:28 | call to user_input | call to user_input | | complex.cpp:42:18:42:18 | call to a | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:55:19:55:28 | call to user_input | call to user_input | | complex.cpp:43:18:43:18 | call to b | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:43:18:43:18 | call to b | call to b flows from $@ | complex.cpp:54:19:54:28 | call to user_input | call to user_input | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWriteProductFlow.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWriteProductFlow.expected index 528d164b888..e1665c23315 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWriteProductFlow.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWriteProductFlow.expected @@ -1,8 +1,9 @@ edges | test.cpp:16:11:16:21 | mk_string_t indirection [string] | test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | | test.cpp:18:5:18:30 | ... = ... | test.cpp:18:10:18:15 | str indirection [post update] [string] | -| test.cpp:18:10:18:15 | str indirection [post update] [string] | test.cpp:16:11:16:21 | mk_string_t indirection [string] | +| test.cpp:18:10:18:15 | str indirection [post update] [string] | test.cpp:19:5:19:7 | str indirection [string] | | test.cpp:18:19:18:24 | call to malloc | test.cpp:18:5:18:30 | ... = ... | +| test.cpp:19:5:19:7 | str indirection [string] | test.cpp:16:11:16:21 | mk_string_t indirection [string] | | test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:42:13:42:15 | str indirection [string] | | test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:72:17:72:19 | str indirection [string] | | test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | test.cpp:80:17:80:19 | str indirection [string] | @@ -17,8 +18,9 @@ edges | test.cpp:80:22:80:27 | string indirection | test.cpp:80:22:80:27 | string | | test.cpp:88:11:88:30 | mk_string_t_plus_one indirection [string] | test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | | test.cpp:90:5:90:34 | ... = ... | test.cpp:90:10:90:15 | str indirection [post update] [string] | -| test.cpp:90:10:90:15 | str indirection [post update] [string] | test.cpp:88:11:88:30 | mk_string_t_plus_one indirection [string] | +| test.cpp:90:10:90:15 | str indirection [post update] [string] | test.cpp:91:5:91:7 | str indirection [string] | | test.cpp:90:19:90:24 | call to malloc | test.cpp:90:5:90:34 | ... = ... | +| test.cpp:91:5:91:7 | str indirection [string] | test.cpp:88:11:88:30 | mk_string_t_plus_one indirection [string] | | test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:99:13:99:15 | str indirection [string] | | test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:129:17:129:19 | str indirection [string] | | test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | test.cpp:137:17:137:19 | str indirection [string] | @@ -32,16 +34,17 @@ edges | test.cpp:137:17:137:19 | str indirection [string] | test.cpp:137:22:137:27 | string indirection | | test.cpp:137:22:137:27 | string indirection | test.cpp:137:22:137:27 | string | | test.cpp:147:5:147:34 | ... = ... | test.cpp:147:10:147:15 | str indirection [post update] [string] | -| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:152:13:152:15 | str indirection [string] | -| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:154:13:154:15 | str indirection [string] | -| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:156:13:156:15 | str indirection [string] | -| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:175:17:175:19 | str indirection [string] | -| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:187:17:187:19 | str indirection [string] | -| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:195:17:195:19 | str indirection [string] | -| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:199:17:199:19 | str indirection [string] | -| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:203:17:203:19 | str indirection [string] | -| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:207:17:207:19 | str indirection [string] | +| test.cpp:147:10:147:15 | str indirection [post update] [string] | test.cpp:148:5:148:7 | str indirection [string] | | test.cpp:147:19:147:24 | call to malloc | test.cpp:147:5:147:34 | ... = ... | +| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:152:13:152:15 | str indirection [string] | +| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:154:13:154:15 | str indirection [string] | +| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:156:13:156:15 | str indirection [string] | +| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:175:17:175:19 | str indirection [string] | +| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:187:17:187:19 | str indirection [string] | +| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:195:17:195:19 | str indirection [string] | +| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:199:17:199:19 | str indirection [string] | +| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:203:17:203:19 | str indirection [string] | +| test.cpp:148:5:148:7 | str indirection [string] | test.cpp:207:17:207:19 | str indirection [string] | | test.cpp:152:13:152:15 | str indirection [string] | test.cpp:152:18:152:23 | string | | test.cpp:152:13:152:15 | str indirection [string] | test.cpp:152:18:152:23 | string indirection | | test.cpp:152:18:152:23 | string indirection | test.cpp:152:18:152:23 | string | @@ -91,6 +94,7 @@ nodes | test.cpp:18:5:18:30 | ... = ... | semmle.label | ... = ... | | test.cpp:18:10:18:15 | str indirection [post update] [string] | semmle.label | str indirection [post update] [string] | | test.cpp:18:19:18:24 | call to malloc | semmle.label | call to malloc | +| test.cpp:19:5:19:7 | str indirection [string] | semmle.label | str indirection [string] | | test.cpp:39:21:39:31 | call to mk_string_t indirection [string] | semmle.label | call to mk_string_t indirection [string] | | test.cpp:42:13:42:15 | str indirection [string] | semmle.label | str indirection [string] | | test.cpp:42:18:42:23 | string | semmle.label | string | @@ -105,6 +109,7 @@ nodes | test.cpp:90:5:90:34 | ... = ... | semmle.label | ... = ... | | test.cpp:90:10:90:15 | str indirection [post update] [string] | semmle.label | str indirection [post update] [string] | | test.cpp:90:19:90:24 | call to malloc | semmle.label | call to malloc | +| test.cpp:91:5:91:7 | str indirection [string] | semmle.label | str indirection [string] | | test.cpp:96:21:96:40 | call to mk_string_t_plus_one indirection [string] | semmle.label | call to mk_string_t_plus_one indirection [string] | | test.cpp:99:13:99:15 | str indirection [string] | semmle.label | str indirection [string] | | test.cpp:99:18:99:23 | string | semmle.label | string | @@ -118,6 +123,7 @@ nodes | test.cpp:147:5:147:34 | ... = ... | semmle.label | ... = ... | | test.cpp:147:10:147:15 | str indirection [post update] [string] | semmle.label | str indirection [post update] [string] | | test.cpp:147:19:147:24 | call to malloc | semmle.label | call to malloc | +| test.cpp:148:5:148:7 | str indirection [string] | semmle.label | str indirection [string] | | test.cpp:152:13:152:15 | str indirection [string] | semmle.label | str indirection [string] | | test.cpp:152:18:152:23 | string | semmle.label | string | | test.cpp:152:18:152:23 | string indirection | semmle.label | string indirection | From c7e5dc2e9e48dbd57561272da01a5f2fd4741097 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 26 Jun 2023 12:18:05 +0200 Subject: [PATCH 314/364] C++: Fix QLDoc issues --- .../code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 11a4b817dbf..209d0246832 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -1833,6 +1833,9 @@ class Content extends TContent { path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 } + /** Gets the indirection index of this `Content`. */ + abstract int getIndirectionIndex(); + /** * INTERNAL: Do not use. * @@ -1843,15 +1846,6 @@ class Content extends TContent { * the form `*f` is also cleared. */ abstract predicate impliesClearOf(Content c); - - abstract int getIndirectionIndex(); -} - -predicate foo(FieldContent f) { - exists(int i, Field ff | - i = f.getIndirectionIndex() and - ff = f.getField() - ) } /** A reference through a non-union instance field. */ @@ -1869,6 +1863,7 @@ class FieldContent extends Content, TFieldContent { Field getField() { result = f } + /** Gets the indirection index of this `FieldContent`. */ pragma[inline] override int getIndirectionIndex() { pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex) From b87bf46c30199560e7245fc9f4650137d4c90c8c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 26 Jun 2023 11:28:32 +0100 Subject: [PATCH 315/364] C++: Fix joins. --- .../Security/CWE/CWE-193/InvalidPointerDeref.ql | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql index 4249f3a12b9..7b4f1775a07 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -131,8 +131,10 @@ module Barrier2 { } Instruction getABarrierInstruction(FlowState2 state) { - exists(IRGuardCondition g, ValueNumber value, boolean edge | - operandGuardChecks(g, value.getAUse(), _, state, edge) and + exists(IRGuardCondition g, ValueNumber value, Operand use, boolean edge | + use = value.getAUse() and + operandGuardChecks(pragma[only_bind_into](g), pragma[only_bind_into](use), _, + pragma[only_bind_into](state), pragma[only_bind_into](edge)) and result = value.getAnInstruction() and g.controls(result.getBlock(), edge) ) @@ -239,11 +241,13 @@ pragma[nomagic] predicate pointerAddInstructionHasBounds( PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta ) { - exists(Instruction right | + exists(Instruction right, Instruction instr2 | pai.getRight() = right and pai.getLeft() = sink1.asInstruction() and - bounded1(right, sink2.asInstruction(), delta) and - not [right, sink2.asInstruction()] = Barrier2::getABarrierInstruction(delta) + instr2 = sink2.asInstruction() and + bounded1(right, instr2, delta) and + not right = Barrier2::getABarrierInstruction(delta) and + not instr2 = Barrier2::getABarrierInstruction(delta) ) } From 3b4f2b22d65dc9de7b7df140b043243bd87bee6b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 26 Jun 2023 11:36:56 +0100 Subject: [PATCH 316/364] C++: Fix Code Scanning errors. --- .../CWE/CWE-193/ConstantSizeArrayOffByOne.ql | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql index b3258a6e627..eebcce6baea 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql @@ -94,18 +94,21 @@ predicate constantUpperBounded(PointerArithmeticInstruction pai, int delta) { } bindingset[pai, size] -predicate pointerArithOverflow0Impl(PointerArithmeticInstruction pai, int size, int bound, int delta) { - constantUpperBounded(pai, bound) and - delta = bound - size and - delta >= 0 and - size != 0 and - size != 1 +predicate pointerArithOverflow0Impl(PointerArithmeticInstruction pai, int size, int delta) { + exists(int bound | + constantUpperBounded(pai, bound) and + delta = bound - size and + delta >= 0 and + size != 0 and + size != 1 + ) } +pragma[nomagic] predicate pointerArithOverflow0(PointerArithmeticInstruction pai, int delta) { - exists(int size, int bound | + exists(int size | arrayTypeHasSizes(_, pai.getElementSize(), size) and - pointerArithOverflow0Impl(pai, size, bound, delta) + pointerArithOverflow0Impl(pai, size, delta) ) } @@ -130,7 +133,7 @@ bindingset[v] predicate finalPointerArithOverflow(Variable v, PointerArithmeticInstruction pai, int delta) { exists(int size | arrayTypeHasSizes(pragma[only_bind_out](v.getUnspecifiedType()), pai.getElementSize(), size) and - pointerArithOverflow0Impl(pai, size, _, delta) + pointerArithOverflow0Impl(pai, size, delta) ) } From d68b0605cdee725fb63954734d9860e8f0d5d4f0 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 26 Jun 2023 11:37:35 +0100 Subject: [PATCH 317/364] C++: Use 'arrayTypeCand' in 'isSourceImpl' instead of checking for array size explicitly. --- .../Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql index eebcce6baea..42afc6f2119 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql @@ -78,7 +78,10 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string ) } -predicate arrayTypeCand(ArrayType arrayType) { any(Variable v).getUnspecifiedType() = arrayType } +predicate arrayTypeCand(ArrayType arrayType) { + any(Variable v).getUnspecifiedType() = arrayType and + exists(arrayType.getArraySize()) +} pragma[nomagic] predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int arraySize) { @@ -143,7 +146,7 @@ predicate isSourceImpl(DataFlow::Node source, Variable v) { or source.asInstruction().(VariableAddressInstruction).getAstVariable() = v ) and - exists(v.getUnspecifiedType().(ArrayType).getArraySize()) + arrayTypeCand(v.getUnspecifiedType()) } module ArrayAddressToDerefConfig implements DataFlow::StateConfigSig { From 527b537fee11ba879b10ced8b5215a81628598d1 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema <93738568+jketema@users.noreply.github.com> Date: Mon, 26 Jun 2023 12:57:43 +0200 Subject: [PATCH 318/364] Apply suggestions from code review Co-authored-by: Mathias Vorreiter Pedersen --- cpp/ql/test/library-tests/dataflow/fields/clearning.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/clearning.cpp b/cpp/ql/test/library-tests/dataflow/fields/clearning.cpp index cdcc0c7afac..0347c6725d2 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/clearning.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/clearning.cpp @@ -17,14 +17,14 @@ void test() S s; **s.x = user_input(); *s.x = 0; - sink(**s.x); // $ clean, as *s.x was overwritten and that contains the tainted **s.x + sink(**s.x); // clean, as *s.x was overwritten and that contains the tainted **s.x } { S s; **s.x = user_input(); **s.x = 0; - sink(**s.x); // $ clean, as **s.x was overwritten and tainted + sink(**s.x); // clean, as **s.x was overwritten and tainted } { From ef9d910a0704a626a939b0170d0bc6d536bd6158 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 26 Jun 2023 15:28:30 +0200 Subject: [PATCH 319/364] Update ruby/ql/lib/codeql/ruby/ApiGraphs.qll Co-authored-by: Erik Krogh Kristensen --- ruby/ql/lib/codeql/ruby/ApiGraphs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll index aaa80c3c205..71b7ddda9fd 100644 --- a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll +++ b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll @@ -108,7 +108,7 @@ module API { * * ### Backward data flow and classes * - * When inspecting the arguments of call, and the value flowing into that argument is a user-defined class (or an instance thereof), + * When inspecting the arguments of a call, and the value flowing into that argument is a user-defined class (or an instance thereof), * uses of `getMethod` will find method definitions in that class (including inherited ones) rather than finding method calls. * * This example illustrates how this can be used to model cases where the library calls a specific named method on a user-defined class: From b61e823cab82cd21929079b32fb3fb2901cf4e07 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 26 Jun 2023 15:31:18 +0200 Subject: [PATCH 320/364] Ruby: clarify qldoc for getADescendentModule --- ruby/ql/lib/codeql/ruby/ApiGraphs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll index 71b7ddda9fd..f6c130eaa1c 100644 --- a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll +++ b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll @@ -253,7 +253,7 @@ module API { deprecated DataFlow::CallNode getCallNode() { this = Impl::MkMethodAccessNode(result) } /** - * Gets a module that descends from the value referenced by this API node. + * Gets a module or class that descends from the module or class referenced by this API node. */ bindingset[this] pragma[inline_late] From f6e244995a0492bd5b4c4fc150e8a8b70e99aeee Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 26 Jun 2023 15:32:11 +0200 Subject: [PATCH 321/364] Update ruby/ql/lib/codeql/ruby/ApiGraphs.qll Co-authored-by: Erik Krogh Kristensen --- ruby/ql/lib/codeql/ruby/ApiGraphs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll index f6c130eaa1c..2dd070ee0df 100644 --- a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll +++ b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll @@ -298,7 +298,7 @@ module API { } /** - * Gets an access to a constant with this valeu as the base of the access. + * Gets an access to a constant with this value as the base of the access. * * This is equivalent to `getMember(_)` but can be more efficient. */ From 8a43fc81ee3406b8e9a4bc4dabf436928c51f97a Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Mon, 26 Jun 2023 15:52:52 +0100 Subject: [PATCH 322/364] Java: Tweak some android tests They were all failing for me like: [autobuild] /home/ian/code/dev/target/codeql-java-integration-tests/ql/java/ql/integration-tests/all-platforms/java/android-sample-old-style-no-wrapper/project/src/main/AndroidManifest.xml:5: Error: Main must extend android.app.Activity [Instantiatable] [autobuild] [autobuild] ~~~~ [autobuild] Explanation for issues of type "Instantiatable": [autobuild] Activities, services, broadcast receivers etc. registered in the manifest [autobuild] file (or for custom views, in a layout file) must be "instantiatable" by [autobuild] the system, which means that the class must be public, it must have an [autobuild] empty public constructor, and if it's an inner class, it must be a static [autobuild] inner class. I'm not sure why it works on CI but not locally, but either way this works around the issue. --- .../project/build.gradle.kts | 3 +++ .../test.expected | 1 + .../project/build.gradle.kts | 3 +++ .../test.expected | 1 + .../android-sample-old-style-no-wrapper/project/build.gradle | 4 ++++ .../java/android-sample-old-style-no-wrapper/test.expected | 1 + .../java/android-sample-old-style/project/build.gradle | 4 ++++ .../all-platforms/java/android-sample-old-style/test.expected | 1 + 8 files changed, 18 insertions(+) diff --git a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script-no-wrapper/project/build.gradle.kts b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script-no-wrapper/project/build.gradle.kts index 95b77607cb3..75f63e5d4c4 100644 --- a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script-no-wrapper/project/build.gradle.kts +++ b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script-no-wrapper/project/build.gradle.kts @@ -54,6 +54,9 @@ android { versionName = "1.0" } + lintOptions { + disable("Instantiatable") + } } androidComponents { diff --git a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script-no-wrapper/test.expected b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script-no-wrapper/test.expected index 5ea6cd8c5ca..94266bb00a1 100644 --- a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script-no-wrapper/test.expected +++ b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script-no-wrapper/test.expected @@ -13,6 +13,7 @@ xmlFiles | project/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml | | project/build/intermediates/incremental/mergeReleaseResources/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseResources/merger.xml | | project/build/intermediates/incremental/mergeReleaseShaders/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseShaders/merger.xml | +| project/build/intermediates/lint_vital_partial_results/release/out/lint-issues-release.xml:0:0:0:0 | project/build/intermediates/lint_vital_partial_results/release/out/lint-issues-release.xml | | project/build/intermediates/merged_manifest/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/merged_manifest/release/AndroidManifest.xml | | project/build/intermediates/merged_manifests/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/merged_manifests/release/AndroidManifest.xml | | project/build/intermediates/packaged_manifests/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/packaged_manifests/release/AndroidManifest.xml | diff --git a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script/project/build.gradle.kts b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script/project/build.gradle.kts index 95b77607cb3..75f63e5d4c4 100644 --- a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script/project/build.gradle.kts +++ b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script/project/build.gradle.kts @@ -54,6 +54,9 @@ android { versionName = "1.0" } + lintOptions { + disable("Instantiatable") + } } androidComponents { diff --git a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script/test.expected b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script/test.expected index 5ea6cd8c5ca..94266bb00a1 100644 --- a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script/test.expected +++ b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-kotlin-build-script/test.expected @@ -13,6 +13,7 @@ xmlFiles | project/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml | | project/build/intermediates/incremental/mergeReleaseResources/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseResources/merger.xml | | project/build/intermediates/incremental/mergeReleaseShaders/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseShaders/merger.xml | +| project/build/intermediates/lint_vital_partial_results/release/out/lint-issues-release.xml:0:0:0:0 | project/build/intermediates/lint_vital_partial_results/release/out/lint-issues-release.xml | | project/build/intermediates/merged_manifest/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/merged_manifest/release/AndroidManifest.xml | | project/build/intermediates/merged_manifests/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/merged_manifests/release/AndroidManifest.xml | | project/build/intermediates/packaged_manifests/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/packaged_manifests/release/AndroidManifest.xml | diff --git a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-no-wrapper/project/build.gradle b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-no-wrapper/project/build.gradle index 7751b92ae54..4d52801f178 100644 --- a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-no-wrapper/project/build.gradle +++ b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-no-wrapper/project/build.gradle @@ -55,4 +55,8 @@ android { } variantFilter { variant -> if (variant.buildType.name == "debug") { setIgnore(true) } } + + lintOptions { + disable "Instantiatable" + } } diff --git a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-no-wrapper/test.expected b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-no-wrapper/test.expected index 5ea6cd8c5ca..94266bb00a1 100644 --- a/java/ql/integration-tests/all-platforms/java/android-sample-old-style-no-wrapper/test.expected +++ b/java/ql/integration-tests/all-platforms/java/android-sample-old-style-no-wrapper/test.expected @@ -13,6 +13,7 @@ xmlFiles | project/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml | | project/build/intermediates/incremental/mergeReleaseResources/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseResources/merger.xml | | project/build/intermediates/incremental/mergeReleaseShaders/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseShaders/merger.xml | +| project/build/intermediates/lint_vital_partial_results/release/out/lint-issues-release.xml:0:0:0:0 | project/build/intermediates/lint_vital_partial_results/release/out/lint-issues-release.xml | | project/build/intermediates/merged_manifest/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/merged_manifest/release/AndroidManifest.xml | | project/build/intermediates/merged_manifests/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/merged_manifests/release/AndroidManifest.xml | | project/build/intermediates/packaged_manifests/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/packaged_manifests/release/AndroidManifest.xml | diff --git a/java/ql/integration-tests/all-platforms/java/android-sample-old-style/project/build.gradle b/java/ql/integration-tests/all-platforms/java/android-sample-old-style/project/build.gradle index 7751b92ae54..4d52801f178 100644 --- a/java/ql/integration-tests/all-platforms/java/android-sample-old-style/project/build.gradle +++ b/java/ql/integration-tests/all-platforms/java/android-sample-old-style/project/build.gradle @@ -55,4 +55,8 @@ android { } variantFilter { variant -> if (variant.buildType.name == "debug") { setIgnore(true) } } + + lintOptions { + disable "Instantiatable" + } } diff --git a/java/ql/integration-tests/all-platforms/java/android-sample-old-style/test.expected b/java/ql/integration-tests/all-platforms/java/android-sample-old-style/test.expected index 5ea6cd8c5ca..94266bb00a1 100644 --- a/java/ql/integration-tests/all-platforms/java/android-sample-old-style/test.expected +++ b/java/ql/integration-tests/all-platforms/java/android-sample-old-style/test.expected @@ -13,6 +13,7 @@ xmlFiles | project/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml | | project/build/intermediates/incremental/mergeReleaseResources/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseResources/merger.xml | | project/build/intermediates/incremental/mergeReleaseShaders/merger.xml:0:0:0:0 | project/build/intermediates/incremental/mergeReleaseShaders/merger.xml | +| project/build/intermediates/lint_vital_partial_results/release/out/lint-issues-release.xml:0:0:0:0 | project/build/intermediates/lint_vital_partial_results/release/out/lint-issues-release.xml | | project/build/intermediates/merged_manifest/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/merged_manifest/release/AndroidManifest.xml | | project/build/intermediates/merged_manifests/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/merged_manifests/release/AndroidManifest.xml | | project/build/intermediates/packaged_manifests/release/AndroidManifest.xml:0:0:0:0 | project/build/intermediates/packaged_manifests/release/AndroidManifest.xml | From 54632cd474e035524723e165a9a7ddee6a58102f Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 26 Jun 2023 20:04:14 +0200 Subject: [PATCH 323/364] C++: Replace `not exists` by `forex` in `clearsContent` --- .../code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 85a4a224e52..838a660432f 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -785,11 +785,10 @@ predicate clearsContent(Node n, Content c) { p.getAnOperand() = op.getUse().getAst() ) or - not exists(PostUpdateNode pun, Content d | - d.impliesClearOf(c) and - storeStepImpl(_, d, pun, true) and - c.getIndirectionIndex() > d.getIndirectionIndex() and - pun.getPreUpdateNode() = n + forex(PostUpdateNode pun, Content d | + d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) and pun.getPreUpdateNode() = n + | + c.getIndirectionIndex() = d.getIndirectionIndex() ) ) } From ef383a135d506a4a996ec486f126d8ed84b09c4c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 26 Jun 2023 19:09:43 +0100 Subject: [PATCH 324/364] C++: Prune the set of interesting pointer-arithmetic instructions by another flow. --- .../CWE/CWE-193/InvalidPointerDeref.ql | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql index 7b4f1775a07..6659b820659 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -241,6 +241,7 @@ pragma[nomagic] predicate pointerAddInstructionHasBounds( PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta ) { + InterestingPointerAddInstruction::isInteresting(pragma[only_bind_into](pai)) and exists(Instruction right, Instruction instr2 | pai.getRight() = right and pai.getLeft() = sink1.asInstruction() and @@ -251,6 +252,29 @@ predicate pointerAddInstructionHasBounds( ) } +module InterestingPointerAddInstruction { + private module PointerAddInstructionConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + // The sources is the same as in the sources for the second + // projection in the `AllocToInvalidPointerConfig` module. + hasSize(source.asConvertedExpr(), _, _) + } + + predicate isSink(DataFlow::Node sink) { + sink.asInstruction() = any(PointerAddInstruction pai).getLeft() + } + } + + private import DataFlow::Global + + predicate isInteresting(PointerAddInstruction pai) { + exists(DataFlow::Node n | + n.asInstruction() = pai.getLeft() and + flowTo(n) + ) + } +} + /** * Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the * left operand of the pointer-arithmetic operation. From aff4066020cdc6782fd3a9a24b3fbc761f22449f Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 26 Jun 2023 15:39:09 -0400 Subject: [PATCH 325/364] C++: improve irreducible back edge detection --- .../new/internal/semantic/SemanticSSA.qll | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll index 65c0efec4aa..a02760a9f2a 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll @@ -70,21 +70,26 @@ predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionP // Conservatively assume that every edge is a back edge if we don't have dominance information. ( phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or - trimmedReachable(phi.getBasicBlock(), edge.getOrigBlock()) or + irreducibleSccEdge(phi.getBasicBlock(), edge.getOrigBlock()) or not edge.getOrigBlock().hasDominanceInformation() ) } -private predicate trimmedReachable(SemBasicBlock b1, SemBasicBlock b2) { - b1 = b2 - or - exists(SemBasicBlock mid | - trimmedReachable(b1, mid) and - trimmedEdges(mid, b2) - ) +/** + * Holds if the edge from b1 to b2 is part of a multiple-entry cycle in an irreducible control flow + * graph. + * + * An ireducible control flow graph is one where the usual dominance-based back edge detection does + * not work, because there is a cycle with multiple entry points, meaning there are + * mutually-reachable basic blocks where neither dominates the other. For such a graph, we first + * all detectable back-edges using the normal condition that the predecessor block is dominated by + * the successor block, then mark all edges in a cycle in the resulting graph as back edges. + */ +private predicate irreducibleSccEdge(SemBasicBlock b1, SemBasicBlock b2) { + trimmedEdge(b1, b2) and trimmedEdge+(b2, b1) } -private predicate trimmedEdges(SemBasicBlock pred, SemBasicBlock succ) { +private predicate trimmedEdge(SemBasicBlock pred, SemBasicBlock succ) { pred.getASuccessor() = succ and not succ.bbDominates(pred) } From dcb349434cf65b1d5bfe2c390ebfd24e01dab2f3 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 26 Jun 2023 15:52:32 -0400 Subject: [PATCH 326/364] C++: fix comment formatting --- .../rangeanalysis/new/internal/semantic/SemanticSSA.qll | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll index a02760a9f2a..1a5a30d1454 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll @@ -78,12 +78,13 @@ predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionP /** * Holds if the edge from b1 to b2 is part of a multiple-entry cycle in an irreducible control flow * graph. - * + * * An ireducible control flow graph is one where the usual dominance-based back edge detection does * not work, because there is a cycle with multiple entry points, meaning there are * mutually-reachable basic blocks where neither dominates the other. For such a graph, we first - * all detectable back-edges using the normal condition that the predecessor block is dominated by - * the successor block, then mark all edges in a cycle in the resulting graph as back edges. + * remove all detectable back-edges using the normal condition that the predecessor block is + * dominated by the successor block, then mark all edges in a cycle in the resulting graph as back + * edges. */ private predicate irreducibleSccEdge(SemBasicBlock b1, SemBasicBlock b2) { trimmedEdge(b1, b2) and trimmedEdge+(b2, b1) From d42f6a08be2392c93d7b1a03a55ceeafbda59ace Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 27 Jun 2023 09:26:48 +0200 Subject: [PATCH 327/364] Document deprecated imports --- docs/codeql/ql-language-reference/annotations.rst | 2 +- docs/codeql/ql-language-reference/modules.rst | 7 ++++++- .../ql-language-reference/ql-language-specification.rst | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/codeql/ql-language-reference/annotations.rst b/docs/codeql/ql-language-reference/annotations.rst index 70e4321667f..c87b479857e 100644 --- a/docs/codeql/ql-language-reference/annotations.rst +++ b/docs/codeql/ql-language-reference/annotations.rst @@ -126,7 +126,7 @@ body must also be annotated with ``cached``, otherwise a compiler error is repor ``deprecated`` ============== -**Available for**: |classes|, |algebraic datatypes|, |member predicates|, |non-member predicates|, |fields|, |modules|, |aliases| +**Available for**: |classes|, |algebraic datatypes|, |member predicates|, |non-member predicates|, |imports|, |fields|, |modules|, |aliases| The ``deprecated`` annotation is applied to names that are outdated and scheduled for removal in a future release of QL. diff --git a/docs/codeql/ql-language-reference/modules.rst b/docs/codeql/ql-language-reference/modules.rst index 42344c72e3d..ec4097ae019 100644 --- a/docs/codeql/ql-language-reference/modules.rst +++ b/docs/codeql/ql-language-reference/modules.rst @@ -264,7 +264,12 @@ Import statements are used for importing modules. They are of the form: Import statements are usually listed at the beginning of the module. Each import statement imports one module. You can import multiple modules by including multiple import statements (one for each module you want to import). -An import statement can also be :ref:`annotated ` with ``private``. + +An import statement can also be :ref:`annotated ` with +``private`` or ``deprecated``. If an import statement is annotated with +``private`` then the imported names are not reexported. If an imported name is +only reachable through deprecated imports in a given context then usage of the +name in that context will generate deprecation warnings. You can import a module under a different name using the ``as`` keyword, for example ``import javascript as js``. diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst index e1e2dad10fa..9328a0f3ec3 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -794,7 +794,7 @@ The following table summarizes the syntactic constructs which can be marked with +----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+ | ``private`` | yes | | yes | yes | yes | yes | yes | yes | yes | +----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+ -| ``deprecated`` | yes | | yes | yes | | yes | yes | yes | yes | +| ``deprecated`` | yes | | yes | yes | yes | yes | yes | yes | yes | +----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+ | ``override`` | | | yes | | | yes | | | | +----------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+------------+ From 160771e673369f31139afef0b21efb60a378f92b Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 23 Jun 2023 13:27:10 +0200 Subject: [PATCH 328/364] C#: Avoid combinatorial explosions in GVN construction for types --- .../consistency-queries/TypeConsistency.qll | 13 ++++++ .../lib/semmle/code/csharp/AnnotatedType.qll | 2 + csharp/ql/lib/semmle/code/csharp/Generics.qll | 19 +++++---- csharp/ql/lib/semmle/code/csharp/Type.qll | 17 ++++---- csharp/ql/lib/semmle/code/csharp/TypeRef.qll | 2 +- .../ql/lib/semmle/code/csharp/Unification.qll | 42 +++++++++++-------- csharp/ql/lib/semmle/code/dotnet/Generics.qll | 2 +- 7 files changed, 61 insertions(+), 36 deletions(-) create mode 100644 csharp/ql/consistency-queries/TypeConsistency.qll diff --git a/csharp/ql/consistency-queries/TypeConsistency.qll b/csharp/ql/consistency-queries/TypeConsistency.qll new file mode 100644 index 00000000000..37504a2df3f --- /dev/null +++ b/csharp/ql/consistency-queries/TypeConsistency.qll @@ -0,0 +1,13 @@ +import csharp +import semmle.code.csharp.Unification + +query predicate missingGvn(Type t, string cls) { + not exists(Gvn::getGlobalValueNumber(t)) and + cls = t.getPrimaryQlClasses() +} + +query predicate multipleGvn(Type t, Gvn::GvnType g, string cls) { + g = Gvn::getGlobalValueNumber(t) and + strictcount(Gvn::getGlobalValueNumber(t)) > 1 and + cls = t.getPrimaryQlClasses() +} diff --git a/csharp/ql/lib/semmle/code/csharp/AnnotatedType.qll b/csharp/ql/lib/semmle/code/csharp/AnnotatedType.qll index 57221e47aa9..83bffc9b2a8 100644 --- a/csharp/ql/lib/semmle/code/csharp/AnnotatedType.qll +++ b/csharp/ql/lib/semmle/code/csharp/AnnotatedType.qll @@ -401,6 +401,8 @@ class AnnotatedArrayType extends AnnotatedType { class AnnotatedConstructedType extends AnnotatedType { override ConstructedType type; + AnnotatedConstructedType() { not type instanceof NullableType } + /** Gets the `i`th type argument of this constructed type. */ AnnotatedType getTypeArgument(int i) { result.getType() = type.getTypeArgument(i) and diff --git a/csharp/ql/lib/semmle/code/csharp/Generics.qll b/csharp/ql/lib/semmle/code/csharp/Generics.qll index ee850f25ea3..51c1dbc19fd 100644 --- a/csharp/ql/lib/semmle/code/csharp/Generics.qll +++ b/csharp/ql/lib/semmle/code/csharp/Generics.qll @@ -26,7 +26,8 @@ private import TypeRef class Generic extends DotNet::Generic, Declaration, @generic { Generic() { type_parameters(_, _, this, _) or - type_arguments(_, _, this) + type_arguments(_, _, this) or + nullable_underlying_type(this, _) } } @@ -39,7 +40,7 @@ class Generic extends DotNet::Generic, Declaration, @generic { class UnboundGeneric extends DotNet::UnboundGeneric, Generic { UnboundGeneric() { type_parameters(_, _, this, _) } - override TypeParameter getTypeParameter(int n) { type_parameters(result, n, this, _) } + final override TypeParameter getTypeParameter(int n) { type_parameters(result, n, this, _) } override ConstructedGeneric getAConstructedGeneric() { result.getUnboundGeneric() = this } @@ -67,7 +68,11 @@ private string getTypeParameterCommas(UnboundGeneric ug) { * generic method (`ConstructedMethod`). */ class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic { - ConstructedGeneric() { type_arguments(_, _, this) } + ConstructedGeneric() { + type_arguments(_, _, this) + or + nullable_underlying_type(this, _) + } override UnboundGeneric getUnboundGeneric() { constructed_generic(this, result) } @@ -75,8 +80,6 @@ class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic { result = this.getUnboundGeneric().getUnboundDeclaration() } - override int getNumberOfTypeArguments() { result = count(int i | type_arguments(_, i, this)) } - override Type getTypeArgument(int i) { none() } override Type getATypeArgument() { result = this.getTypeArgument(_) } @@ -410,13 +413,13 @@ class ConstructedType extends ValueOrRefType, ConstructedGeneric { override Location getALocation() { result = this.getUnboundDeclaration().getALocation() } - override Type getTypeArgument(int n) { type_arguments(getTypeRef(result), n, getTypeRef(this)) } + override Type getTypeArgument(int n) { type_arguments(getTypeRef(result), n, this) } override UnboundGenericType getUnboundGeneric() { constructed_generic(this, getTypeRef(result)) } final override Type getChild(int n) { result = this.getTypeArgument(n) } - final override string toStringWithTypes() { + override string toStringWithTypes() { result = this.getUndecoratedName() + "<" + getTypeArgumentsToString(this) + ">" } @@ -424,7 +427,7 @@ class ConstructedType extends ValueOrRefType, ConstructedGeneric { result = this.getUndecoratedName() + "<" + getTypeArgumentsNames(this) + ">" } - final override predicate hasQualifiedName(string qualifier, string name) { + override predicate hasQualifiedName(string qualifier, string name) { exists(string name0 | name = name0 + "<" + getTypeArgumentsQualifiedNames(this) + ">" | exists(string enclosing | this.getDeclaringType().hasQualifiedName(qualifier, enclosing) and diff --git a/csharp/ql/lib/semmle/code/csharp/Type.qll b/csharp/ql/lib/semmle/code/csharp/Type.qll index 85fde20e07d..0b1e90fa7d6 100644 --- a/csharp/ql/lib/semmle/code/csharp/Type.qll +++ b/csharp/ql/lib/semmle/code/csharp/Type.qll @@ -974,29 +974,27 @@ class NullType extends RefType, @null_type { /** * A nullable type, for example `int?`. */ -class NullableType extends ValueType, DotNet::ConstructedGeneric, @nullable_type { +class NullableType extends ValueType, ConstructedType, @nullable_type { /** * Gets the underlying value type of this nullable type. * For example `int` in `int?`. */ Type getUnderlyingType() { nullable_underlying_type(this, getTypeRef(result)) } + override UnboundGenericStruct getUnboundGeneric() { + result.hasQualifiedName("System", "Nullable<>") + } + override string toStringWithTypes() { result = this.getUnderlyingType().toStringWithTypes() + "?" } - override Type getChild(int n) { result = this.getUnderlyingType() and n = 0 } - override Location getALocation() { result = this.getUnderlyingType().getALocation() } override Type getTypeArgument(int p) { p = 0 and result = this.getUnderlyingType() } override string getAPrimaryQlClass() { result = "NullableType" } - final override string getName() { - result = "Nullable<" + this.getUnderlyingType().getName() + ">" - } - final override predicate hasQualifiedName(string qualifier, string name) { qualifier = "System" and name = "Nullable<" + this.getUnderlyingType().getQualifiedName() + ">" @@ -1126,7 +1124,10 @@ class ArglistType extends Type, @arglist_type { * A type that could not be resolved. This could happen if an indirect reference * is not available at compilation time. */ -class UnknownType extends Type, @unknown_type { } +class UnknownType extends Type, @unknown_type { + /** Holds if this is the canonical unknown type, and not a type that failed to extract properly. */ + predicate isCanonical() { types(this, _, "") } +} /** * A type representing a tuple. For example, `(int, bool, string)`. diff --git a/csharp/ql/lib/semmle/code/csharp/TypeRef.qll b/csharp/ql/lib/semmle/code/csharp/TypeRef.qll index 7a6de44419f..f13168dd20d 100644 --- a/csharp/ql/lib/semmle/code/csharp/TypeRef.qll +++ b/csharp/ql/lib/semmle/code/csharp/TypeRef.qll @@ -16,7 +16,7 @@ private class TypeRef extends @typeref { typeref_type(this, result) or not typeref_type(this, _) and - result instanceof UnknownType + result.(UnknownType).isCanonical() } } diff --git a/csharp/ql/lib/semmle/code/csharp/Unification.qll b/csharp/ql/lib/semmle/code/csharp/Unification.qll index c3cbbd9ce97..7570070078f 100644 --- a/csharp/ql/lib/semmle/code/csharp/Unification.qll +++ b/csharp/ql/lib/semmle/code/csharp/Unification.qll @@ -15,9 +15,11 @@ module Gvn { * but only if the enclosing type is not a `GenericType`. */ string getNameNested(Type t) { - if not t instanceof NestedType or t.(NestedType).getDeclaringType() instanceof GenericType - then result = t.getName() - else result = getNameNested(t.(NestedType).getDeclaringType()) + "+" + t.getName() + exists(string name | name = t.getName() | + if not t instanceof NestedType or t.(NestedType).getDeclaringType() instanceof GenericType + then result = name + else result = getNameNested(t.(NestedType).getDeclaringType()) + "+" + name + ) } /** @@ -47,8 +49,22 @@ module Gvn { not exists(this.getGenericDeclaringType()) and result = 0 } + /** + * Same as `getChild`, but safe-guards against potential extractor issues where + * multiple children exist at the same index, which may result in a combinatorial + * explosion. + */ + private Type getChildUnique(int i) { + result = unique(Type t | t = this.getChild(i) | t) + or + strictcount(this.getChild(i)) > 1 and + result.(UnknownType).isCanonical() + } + /** Gets the number of arguments of this type, not taking nested types into account. */ - int getNumberOfArgumentsSelf() { result = count(int i | exists(this.getChild(i)) and i >= 0) } + int getNumberOfArgumentsSelf() { + result = count(int i | exists(this.getChildUnique(i)) and i >= 0) + } /** Gets the number of arguments of this type, taking nested types into account. */ int getNumberOfArguments() { @@ -61,7 +77,7 @@ module Gvn { or exists(int offset | offset = this.getNumberOfDeclaringArguments() and - result = this.getChild(i - offset) and + result = this.getChildUnique(i - offset) and i >= offset ) } @@ -91,13 +107,9 @@ module Gvn { int getNumberOfTypeParameters() { this = TPointerTypeKind() and result = 1 or - this = TNullableTypeKind() and result = 1 - or this = TArrayTypeKind(_, _) and result = 1 or - exists(GenericType t | this = TConstructedType(t.getUnboundDeclaration()) | - result = t.getNumberOfArguments() - ) + exists(GenericType t | this = TConstructedType(t) | result = t.getNumberOfArguments()) } /** Gets the unbound declaration type that this kind corresponds to, if any. */ @@ -106,15 +118,12 @@ module Gvn { /** * Gets a textual representation of this kind when applied to arguments `args`. * - * This predicate is restricted to built-in generics (pointers, nullables, and - * arrays). + * This predicate is restricted to built-in generics (pointers and arrays). */ bindingset[args] string toStringBuiltin(string args) { this = TPointerTypeKind() and result = args + "*" or - this = TNullableTypeKind() and result = args + "?" - or exists(int rnk | this = TArrayTypeKind(_, rnk) | result = args + "[" + concat(int i | i in [0 .. rnk - 2] | ",") + "]" ) @@ -135,8 +144,6 @@ module Gvn { CompoundTypeKind getTypeKind(Type t) { result = TPointerTypeKind() and t instanceof PointerType or - result = TNullableTypeKind() and t instanceof NullableType - or t = any(ArrayType at | result = TArrayTypeKind(at.getDimension(), at.getRank())) or result = TConstructedType(t.getUnboundDeclaration()) @@ -280,6 +287,7 @@ module Gvn { pragma[noinline] private predicate toStringPart(int i, int j) { + this.isFullyConstructed() and exists(int offset | exists(GenericType t, int children | t = this.getConstructedGenericDeclaringTypeAt(i) and @@ -449,14 +457,12 @@ module Gvn { cached newtype TCompoundTypeKind = TPointerTypeKind() { Stages::UnificationStage::forceCachingInSameStage() } or - TNullableTypeKind() or TArrayTypeKind(int dim, int rnk) { exists(ArrayType at | dim = at.getDimension() and rnk = at.getRank()) } or TConstructedType(GenericType unboundDecl) { unboundDecl = any(GenericType t).getUnboundDeclaration() and not unboundDecl instanceof PointerType and - not unboundDecl instanceof NullableType and not unboundDecl instanceof ArrayType and not unboundDecl instanceof TupleType } diff --git a/csharp/ql/lib/semmle/code/dotnet/Generics.qll b/csharp/ql/lib/semmle/code/dotnet/Generics.qll index f84718d4b82..67b8fb2f5d0 100644 --- a/csharp/ql/lib/semmle/code/dotnet/Generics.qll +++ b/csharp/ql/lib/semmle/code/dotnet/Generics.qll @@ -41,7 +41,7 @@ abstract class ConstructedGeneric extends Generic { UnboundGeneric getUnboundGeneric() { none() } /** Gets the total number of type arguments. */ - int getNumberOfTypeArguments() { result = count(int i | exists(this.getTypeArgument(i))) } + final int getNumberOfTypeArguments() { result = count(int i | exists(this.getTypeArgument(i))) } } /** From 6869f03ccafb04c75bfbd07a667cc77a7238e79b Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 27 Jun 2023 11:27:16 +0200 Subject: [PATCH 329/364] C#: Enable implicit this warnings for remaining packs --- csharp/downgrades/qlpack.yml | 1 + csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 1 + csharp/ql/campaigns/Solorigate/src/qlpack.yml | 1 + csharp/ql/campaigns/Solorigate/test/qlpack.yml | 1 + csharp/ql/consistency-queries/qlpack.yml | 1 + csharp/ql/examples/qlpack.yml | 1 + csharp/ql/integration-tests/qlpack.yml | 1 + 7 files changed, 7 insertions(+) diff --git a/csharp/downgrades/qlpack.yml b/csharp/downgrades/qlpack.yml index c326f44bb0d..2ffd6b94f29 100644 --- a/csharp/downgrades/qlpack.yml +++ b/csharp/downgrades/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/csharp-downgrades groups: csharp downgrades: . library: true +warnOnImplicitThis: true diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 5f8c63b8ea3..8d19bca1d61 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -6,3 +6,4 @@ groups: library: true dependencies: codeql/csharp-all: ${workspace} +warnOnImplicitThis: true diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index 65153d150f7..6bcc2def6f8 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -7,3 +7,4 @@ defaultSuiteFile: codeql-suites/solorigate.qls dependencies: codeql/csharp-all: ${workspace} codeql/csharp-solorigate-all: ${workspace} +warnOnImplicitThis: true diff --git a/csharp/ql/campaigns/Solorigate/test/qlpack.yml b/csharp/ql/campaigns/Solorigate/test/qlpack.yml index 7093935d651..dfd335f2726 100644 --- a/csharp/ql/campaigns/Solorigate/test/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/test/qlpack.yml @@ -10,3 +10,4 @@ dependencies: codeql/csharp-solorigate-queries: ${workspace} extractor: csharp tests: . +warnOnImplicitThis: true diff --git a/csharp/ql/consistency-queries/qlpack.yml b/csharp/ql/consistency-queries/qlpack.yml index 0d36d5156f5..8afefd18259 100644 --- a/csharp/ql/consistency-queries/qlpack.yml +++ b/csharp/ql/consistency-queries/qlpack.yml @@ -3,3 +3,4 @@ groups: [csharp, test, consistency-queries] dependencies: codeql/csharp-all: ${workspace} extractor: csharp +warnOnImplicitThis: true diff --git a/csharp/ql/examples/qlpack.yml b/csharp/ql/examples/qlpack.yml index ca5ba5a3ab4..8796b678c16 100644 --- a/csharp/ql/examples/qlpack.yml +++ b/csharp/ql/examples/qlpack.yml @@ -4,3 +4,4 @@ groups: - examples dependencies: codeql/csharp-all: ${workspace} +warnOnImplicitThis: true diff --git a/csharp/ql/integration-tests/qlpack.yml b/csharp/ql/integration-tests/qlpack.yml index 972ad51f2cf..e66c1239b04 100644 --- a/csharp/ql/integration-tests/qlpack.yml +++ b/csharp/ql/integration-tests/qlpack.yml @@ -1,2 +1,3 @@ dependencies: codeql/csharp-all: '*' +warnOnImplicitThis: true From ab797065abc78e48bc2b4dfad1ea50fe3ce449d0 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 27 Jun 2023 11:49:37 +0200 Subject: [PATCH 330/364] Go: Enable implicit this warnings for remaining packs --- go/downgrades/qlpack.yml | 1 + go/external-packs/codeql/suite-helpers/0.0.2/qlpack.yml | 1 + go/ql/config/legacy-support/qlpack.yml | 1 + go/ql/examples/qlpack.yml | 1 + go/ql/integration-tests/all-platforms/go/qlpack.yml | 1 + go/ql/integration-tests/linux-only/go/qlpack.yml | 1 + 6 files changed, 6 insertions(+) diff --git a/go/downgrades/qlpack.yml b/go/downgrades/qlpack.yml index d3e056bea64..7e8e0022eb0 100644 --- a/go/downgrades/qlpack.yml +++ b/go/downgrades/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/go-downgrades groups: go downgrades: . library: true +warnOnImplicitThis: true diff --git a/go/external-packs/codeql/suite-helpers/0.0.2/qlpack.yml b/go/external-packs/codeql/suite-helpers/0.0.2/qlpack.yml index ca0a6732f5a..7c42cb6974c 100644 --- a/go/external-packs/codeql/suite-helpers/0.0.2/qlpack.yml +++ b/go/external-packs/codeql/suite-helpers/0.0.2/qlpack.yml @@ -1,3 +1,4 @@ name: codeql/suite-helpers version: 0.0.2 library: true +warnOnImplicitThis: true diff --git a/go/ql/config/legacy-support/qlpack.yml b/go/ql/config/legacy-support/qlpack.yml index bf3ee4d72a6..23ba44acd80 100644 --- a/go/ql/config/legacy-support/qlpack.yml +++ b/go/ql/config/legacy-support/qlpack.yml @@ -2,3 +2,4 @@ name: legacy-libraries-go version: 0.0.0 # Note libraryPathDependencies is obsolete and should not be used in new qlpacks. libraryPathDependencies: codeql-go +warnOnImplicitThis: true diff --git a/go/ql/examples/qlpack.yml b/go/ql/examples/qlpack.yml index 1f2ca2cd40a..006eb3c17b3 100644 --- a/go/ql/examples/qlpack.yml +++ b/go/ql/examples/qlpack.yml @@ -4,3 +4,4 @@ groups: - examples dependencies: codeql/go-all: ${workspace} +warnOnImplicitThis: true diff --git a/go/ql/integration-tests/all-platforms/go/qlpack.yml b/go/ql/integration-tests/all-platforms/go/qlpack.yml index 3a018bff52a..2fc2dd566dd 100644 --- a/go/ql/integration-tests/all-platforms/go/qlpack.yml +++ b/go/ql/integration-tests/all-platforms/go/qlpack.yml @@ -2,3 +2,4 @@ dependencies: codeql/go-all: '*' codeql/go-tests: '*' codeql/go-queries: '*' +warnOnImplicitThis: true diff --git a/go/ql/integration-tests/linux-only/go/qlpack.yml b/go/ql/integration-tests/linux-only/go/qlpack.yml index 3a018bff52a..2fc2dd566dd 100644 --- a/go/ql/integration-tests/linux-only/go/qlpack.yml +++ b/go/ql/integration-tests/linux-only/go/qlpack.yml @@ -2,3 +2,4 @@ dependencies: codeql/go-all: '*' codeql/go-tests: '*' codeql/go-queries: '*' +warnOnImplicitThis: true From 7fcdefbe70b6b85f16dc51e1ba6e343ba08e9a1c Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 27 Jun 2023 11:54:13 +0200 Subject: [PATCH 331/364] Java: Enable implicit this warnings for remaining packs --- java/downgrades/qlpack.yml | 1 + java/ql/consistency-queries/qlpack.yml | 1 + java/ql/examples/qlpack.yml | 1 + java/ql/integration-tests/all-platforms/java/qlpack.yml | 1 + .../all-platforms/kotlin/annotation-id-consistency/qlpack.yml | 1 + .../all-platforms/kotlin/default-parameter-mad-flow/qlpack.yml | 1 + .../kotlin/gradle_kotlinx_serialization/qlpack.yml | 1 + .../kotlin/kotlin-interface-inherited-default/qlpack.yml | 1 + .../all-platforms/kotlin/kotlin_java_static_fields/qlpack.yml | 1 + java/ql/integration-tests/all-platforms/kotlin/qlpack.yml | 1 + .../linux-only/kotlin/custom_plugin/qlpack.yml | 1 + java/ql/integration-tests/linux-only/kotlin/qlpack.yml | 1 + java/ql/integration-tests/posix-only/kotlin/qlpack.yml | 2 +- 13 files changed, 13 insertions(+), 1 deletion(-) diff --git a/java/downgrades/qlpack.yml b/java/downgrades/qlpack.yml index b5a0f1bf411..6489ad2d9f6 100644 --- a/java/downgrades/qlpack.yml +++ b/java/downgrades/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/java-downgrades groups: java downgrades: . library: true +warnOnImplicitThis: true diff --git a/java/ql/consistency-queries/qlpack.yml b/java/ql/consistency-queries/qlpack.yml index e5ab40251bb..1501c7fa736 100644 --- a/java/ql/consistency-queries/qlpack.yml +++ b/java/ql/consistency-queries/qlpack.yml @@ -2,3 +2,4 @@ name: codeql-java-consistency-queries version: 0.0.0 dependencies: codeql/java-all: '*' +warnOnImplicitThis: true diff --git a/java/ql/examples/qlpack.yml b/java/ql/examples/qlpack.yml index 25699c305b0..bbd44274625 100644 --- a/java/ql/examples/qlpack.yml +++ b/java/ql/examples/qlpack.yml @@ -4,3 +4,4 @@ groups: - examples dependencies: codeql/java-all: ${workspace} +warnOnImplicitThis: true diff --git a/java/ql/integration-tests/all-platforms/java/qlpack.yml b/java/ql/integration-tests/all-platforms/java/qlpack.yml index 9ead02fc564..4994af85a75 100644 --- a/java/ql/integration-tests/all-platforms/java/qlpack.yml +++ b/java/ql/integration-tests/all-platforms/java/qlpack.yml @@ -2,3 +2,4 @@ dependencies: codeql/java-all: '*' codeql/java-tests: '*' codeql/java-queries: '*' +warnOnImplicitThis: true diff --git a/java/ql/integration-tests/all-platforms/kotlin/annotation-id-consistency/qlpack.yml b/java/ql/integration-tests/all-platforms/kotlin/annotation-id-consistency/qlpack.yml index 74fbac535d7..eeaa0e9f1b7 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/annotation-id-consistency/qlpack.yml +++ b/java/ql/integration-tests/all-platforms/kotlin/annotation-id-consistency/qlpack.yml @@ -5,3 +5,4 @@ dependencies: codeql/java-queries: '*' dataExtensions: ext/*.model.yml +warnOnImplicitThis: true diff --git a/java/ql/integration-tests/all-platforms/kotlin/default-parameter-mad-flow/qlpack.yml b/java/ql/integration-tests/all-platforms/kotlin/default-parameter-mad-flow/qlpack.yml index f1e981e8791..61fd32f9eb9 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/default-parameter-mad-flow/qlpack.yml +++ b/java/ql/integration-tests/all-platforms/kotlin/default-parameter-mad-flow/qlpack.yml @@ -5,3 +5,4 @@ dependencies: codeql/java-queries: '*' dataExtensions: ext/*.model.yml +warnOnImplicitThis: true diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/qlpack.yml b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/qlpack.yml index 8b18f2ea94a..d9848346b6f 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/qlpack.yml +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/qlpack.yml @@ -3,3 +3,4 @@ dependencies: codeql/java-all: '*' codeql/java-tests: '*' codeql/java-queries: '*' +warnOnImplicitThis: true diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin-interface-inherited-default/qlpack.yml b/java/ql/integration-tests/all-platforms/kotlin/kotlin-interface-inherited-default/qlpack.yml index 814d1059ed5..69d3f0b3658 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/kotlin-interface-inherited-default/qlpack.yml +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin-interface-inherited-default/qlpack.yml @@ -3,3 +3,4 @@ dependencies: codeql/java-all: '*' codeql/java-tests: '*' codeql/java-queries: '*' +warnOnImplicitThis: true diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_java_static_fields/qlpack.yml b/java/ql/integration-tests/all-platforms/kotlin/kotlin_java_static_fields/qlpack.yml index ecc3ee3e4ff..1902aa3a68f 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/kotlin_java_static_fields/qlpack.yml +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_java_static_fields/qlpack.yml @@ -3,3 +3,4 @@ dependencies: codeql/java-all: '*' codeql/java-tests: '*' codeql/java-queries: '*' +warnOnImplicitThis: true diff --git a/java/ql/integration-tests/all-platforms/kotlin/qlpack.yml b/java/ql/integration-tests/all-platforms/kotlin/qlpack.yml index 9ead02fc564..4994af85a75 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/qlpack.yml +++ b/java/ql/integration-tests/all-platforms/kotlin/qlpack.yml @@ -2,3 +2,4 @@ dependencies: codeql/java-all: '*' codeql/java-tests: '*' codeql/java-queries: '*' +warnOnImplicitThis: true diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/qlpack.yml b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/qlpack.yml index e2f6b6de7ba..18ab2b37444 100644 --- a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/qlpack.yml +++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/qlpack.yml @@ -1,3 +1,4 @@ name: integrationtest-custom-plugin dependencies: codeql/java-all: '*' +warnOnImplicitThis: true diff --git a/java/ql/integration-tests/linux-only/kotlin/qlpack.yml b/java/ql/integration-tests/linux-only/kotlin/qlpack.yml index a1e82f7365a..b2ae6491ab8 100644 --- a/java/ql/integration-tests/linux-only/kotlin/qlpack.yml +++ b/java/ql/integration-tests/linux-only/kotlin/qlpack.yml @@ -1,2 +1,3 @@ dependencies: codeql/java-all: '*' +warnOnImplicitThis: true diff --git a/java/ql/integration-tests/posix-only/kotlin/qlpack.yml b/java/ql/integration-tests/posix-only/kotlin/qlpack.yml index 0c0975df53f..4994af85a75 100644 --- a/java/ql/integration-tests/posix-only/kotlin/qlpack.yml +++ b/java/ql/integration-tests/posix-only/kotlin/qlpack.yml @@ -2,4 +2,4 @@ dependencies: codeql/java-all: '*' codeql/java-tests: '*' codeql/java-queries: '*' - +warnOnImplicitThis: true From ab5e241310b39a386bfb1339de25e6998efe9454 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 27 Jun 2023 11:56:29 +0200 Subject: [PATCH 332/364] Javascript: Enable implicit this warnings for remaining packs --- javascript/downgrades/qlpack.yml | 1 + javascript/ql/examples/qlpack.yml | 1 + javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml | 1 + .../ql/experimental/adaptivethreatmodeling/model/qlpack.yml | 1 + .../experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml | 1 + javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml | 1 + .../ql/experimental/adaptivethreatmodeling/test/qlpack.yml | 1 + javascript/ql/integration-tests/all-platforms/qlpack.yml | 1 + 8 files changed, 8 insertions(+) diff --git a/javascript/downgrades/qlpack.yml b/javascript/downgrades/qlpack.yml index b23d7602f30..2ef368fed0b 100644 --- a/javascript/downgrades/qlpack.yml +++ b/javascript/downgrades/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/javascript-downgrades groups: javascript downgrades: . library: true +warnOnImplicitThis: true diff --git a/javascript/ql/examples/qlpack.yml b/javascript/ql/examples/qlpack.yml index 9bd7a0e73a9..75f3cbcb2cd 100644 --- a/javascript/ql/examples/qlpack.yml +++ b/javascript/ql/examples/qlpack.yml @@ -4,3 +4,4 @@ groups: - examples dependencies: codeql/javascript-all: ${workspace} +warnOnImplicitThis: true diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml index addde82c591..cda69768254 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml @@ -8,3 +8,4 @@ groups: - experimental dependencies: codeql/javascript-all: ${workspace} +warnOnImplicitThis: true diff --git a/javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml index e37547ed938..affda0e0b16 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml @@ -6,3 +6,4 @@ groups: - experimental mlModels: - "resources/*.codeqlmodel" +warnOnImplicitThis: true diff --git a/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml index a42eb4067ac..cdf0b9d5aab 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml @@ -8,3 +8,4 @@ groups: dependencies: codeql/javascript-experimental-atm-lib: ${workspace} codeql/javascript-experimental-atm-model: "0.3.1-2023-03-01-12h42m43s.strong-turtle-1xp3dqvv.ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5" +warnOnImplicitThis: true diff --git a/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml index dec06084ef1..6c2930991e4 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml @@ -10,3 +10,4 @@ groups: dependencies: codeql/javascript-experimental-atm-lib: ${workspace} codeql/javascript-experimental-atm-model: "0.3.1-2023-03-01-12h42m43s.strong-turtle-1xp3dqvv.ecb17d40286d14132b481c065a43459a7f0ba9059015b7a49c909c9f9ce5fec5" +warnOnImplicitThis: true diff --git a/javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml index 987b0ef55c4..5a7612bd33c 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/javascript-experimental-atm-tests extractor: javascript dependencies: codeql/javascript-experimental-atm-model-building: ${workspace} +warnOnImplicitThis: true diff --git a/javascript/ql/integration-tests/all-platforms/qlpack.yml b/javascript/ql/integration-tests/all-platforms/qlpack.yml index f4bc24850b4..9f076584585 100644 --- a/javascript/ql/integration-tests/all-platforms/qlpack.yml +++ b/javascript/ql/integration-tests/all-platforms/qlpack.yml @@ -1,3 +1,4 @@ dependencies: codeql/javascript-all: '*' codeql/javascript-queries: '*' +warnOnImplicitThis: true From 2628552ef479503010ff57a4616b0d97a46f8ef3 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 27 Jun 2023 11:59:26 +0200 Subject: [PATCH 333/364] C++: Fix join-order problem in `clearsContent` --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 838a660432f..31915a888ac 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -786,7 +786,9 @@ predicate clearsContent(Node n, Content c) { ) or forex(PostUpdateNode pun, Content d | - d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) and pun.getPreUpdateNode() = n + pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and + storeStepImpl(_, d, pun, true) and + pun.getPreUpdateNode() = n | c.getIndirectionIndex() = d.getIndirectionIndex() ) From f41276cb7fee7bb858f7a717c03d638d1744afc6 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 27 Jun 2023 12:00:13 +0200 Subject: [PATCH 334/364] Python: Enable implicit this warnings for remaining packs --- python/downgrades/qlpack.yml | 1 + python/ql/consistency-queries/qlpack.yml | 1 + python/ql/examples/qlpack.yml | 1 + python/tools/recorded-call-graph-metrics/ql/qlpack.yml | 1 + 4 files changed, 4 insertions(+) diff --git a/python/downgrades/qlpack.yml b/python/downgrades/qlpack.yml index 12755ccb199..0c96e12e7cf 100644 --- a/python/downgrades/qlpack.yml +++ b/python/downgrades/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/python-downgrades groups: python downgrades: . library: true +warnOnImplicitThis: true diff --git a/python/ql/consistency-queries/qlpack.yml b/python/ql/consistency-queries/qlpack.yml index c3433e9fcd6..f74d964dd91 100644 --- a/python/ql/consistency-queries/qlpack.yml +++ b/python/ql/consistency-queries/qlpack.yml @@ -3,3 +3,4 @@ groups: [python, test, consistency-queries] dependencies: codeql/python-all: ${workspace} extractor: python +warnOnImplicitThis: true diff --git a/python/ql/examples/qlpack.yml b/python/ql/examples/qlpack.yml index 96edb7bd844..b3e268d26d6 100644 --- a/python/ql/examples/qlpack.yml +++ b/python/ql/examples/qlpack.yml @@ -4,3 +4,4 @@ groups: - examples dependencies: codeql/python-all: ${workspace} +warnOnImplicitThis: true diff --git a/python/tools/recorded-call-graph-metrics/ql/qlpack.yml b/python/tools/recorded-call-graph-metrics/ql/qlpack.yml index 3fee59d70bc..a08193635d5 100644 --- a/python/tools/recorded-call-graph-metrics/ql/qlpack.yml +++ b/python/tools/recorded-call-graph-metrics/ql/qlpack.yml @@ -3,3 +3,4 @@ version: 0.0.1 extractor: python dependencies: codeql/python-all: '*' +warnOnImplicitThis: true From c9cf0744c09654e756dba18ed4b0a76b05f9c49e Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 27 Jun 2023 12:04:29 +0200 Subject: [PATCH 335/364] QL: Enable implicit this warnings for remaining packs --- ql/ql/consistency-queries/qlpack.yml | 1 + ql/ql/examples/qlpack.yml | 1 + ql/ql/test/callgraph/packs/lib/qlpack.yml | 3 ++- ql/ql/test/callgraph/packs/other/qlpack.yml | 1 + ql/ql/test/callgraph/packs/src/qlpack.yml | 3 ++- ql/ql/test/qlpack.yml | 1 + 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ql/ql/consistency-queries/qlpack.yml b/ql/ql/consistency-queries/qlpack.yml index ffc5cdb7a1a..499d2130ef1 100644 --- a/ql/ql/consistency-queries/qlpack.yml +++ b/ql/ql/consistency-queries/qlpack.yml @@ -3,3 +3,4 @@ groups: [ql, test, consistency-queries] dependencies: codeql/ql: ${workspace} extractor: ql +warnOnImplicitThis: true diff --git a/ql/ql/examples/qlpack.yml b/ql/ql/examples/qlpack.yml index 0652ac37bd5..88fb9314a20 100644 --- a/ql/ql/examples/qlpack.yml +++ b/ql/ql/examples/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/ql-examples groups: [ql, examples] dependencies: codeql/ql: ${workspace} +warnOnImplicitThis: true diff --git a/ql/ql/test/callgraph/packs/lib/qlpack.yml b/ql/ql/test/callgraph/packs/lib/qlpack.yml index 92e83d1e3d8..00c40b2431a 100644 --- a/ql/ql/test/callgraph/packs/lib/qlpack.yml +++ b/ql/ql/test/callgraph/packs/lib/qlpack.yml @@ -1,3 +1,4 @@ name: ql-testing-lib-pack version: 0.1.0 -extractor: ql-test-stuff \ No newline at end of file +extractor: ql-test-stuff +warnOnImplicitThis: true diff --git a/ql/ql/test/callgraph/packs/other/qlpack.yml b/ql/ql/test/callgraph/packs/other/qlpack.yml index d0b95cb68be..e0bc6a0a652 100644 --- a/ql/ql/test/callgraph/packs/other/qlpack.yml +++ b/ql/ql/test/callgraph/packs/other/qlpack.yml @@ -2,3 +2,4 @@ name: ql-other-pack-thing version: 0.1.0 dependencies: ql-testing-src-pack: '*' +warnOnImplicitThis: true diff --git a/ql/ql/test/callgraph/packs/src/qlpack.yml b/ql/ql/test/callgraph/packs/src/qlpack.yml index 2512d8f8483..c0d374d7cb4 100644 --- a/ql/ql/test/callgraph/packs/src/qlpack.yml +++ b/ql/ql/test/callgraph/packs/src/qlpack.yml @@ -1,4 +1,5 @@ name: ql-testing-src-pack version: 0.1.0 dependencies: - ql-testing-lib-pack: ${workspace} \ No newline at end of file + ql-testing-lib-pack: ${workspace} +warnOnImplicitThis: true diff --git a/ql/ql/test/qlpack.yml b/ql/ql/test/qlpack.yml index f31941cdf10..b16fd7e3e20 100644 --- a/ql/ql/test/qlpack.yml +++ b/ql/ql/test/qlpack.yml @@ -5,3 +5,4 @@ dependencies: codeql/ql-examples: ${workspace} extractor: ql tests: . +warnOnImplicitThis: true From 41c071ff741bde00f2d27450c0e290417a42d619 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 27 Jun 2023 12:07:05 +0200 Subject: [PATCH 336/364] Ruby: Enable implicit this warnings for remaining packs --- ruby/downgrades/qlpack.yml | 1 + ruby/ql/consistency-queries/qlpack.yml | 1 + ruby/ql/examples/qlpack.yml | 1 + ruby/ql/integration-tests/all-platforms/qlpack.yml | 1 + 4 files changed, 4 insertions(+) diff --git a/ruby/downgrades/qlpack.yml b/ruby/downgrades/qlpack.yml index c23e8cc44d6..c777eec353c 100644 --- a/ruby/downgrades/qlpack.yml +++ b/ruby/downgrades/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/ruby-downgrades groups: ruby downgrades: . library: true +warnOnImplicitThis: true diff --git a/ruby/ql/consistency-queries/qlpack.yml b/ruby/ql/consistency-queries/qlpack.yml index 707cada6cd2..9a1292eefa0 100644 --- a/ruby/ql/consistency-queries/qlpack.yml +++ b/ruby/ql/consistency-queries/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/ruby-consistency-queries groups: [ruby, test, consistency-queries] dependencies: codeql/ruby-all: ${workspace} +warnOnImplicitThis: true diff --git a/ruby/ql/examples/qlpack.yml b/ruby/ql/examples/qlpack.yml index fc159c65692..5d2cd48bbb9 100644 --- a/ruby/ql/examples/qlpack.yml +++ b/ruby/ql/examples/qlpack.yml @@ -4,3 +4,4 @@ groups: - examples dependencies: codeql/ruby-all: ${workspace} +warnOnImplicitThis: true diff --git a/ruby/ql/integration-tests/all-platforms/qlpack.yml b/ruby/ql/integration-tests/all-platforms/qlpack.yml index a27def4e4d7..5a103c573d4 100644 --- a/ruby/ql/integration-tests/all-platforms/qlpack.yml +++ b/ruby/ql/integration-tests/all-platforms/qlpack.yml @@ -1,3 +1,4 @@ dependencies: codeql/ruby-all: '*' codeql/ruby-queries: '*' +warnOnImplicitThis: true From 8ce09438a02dbbbce00a451a5756a49a9ad0a5fe Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 27 Jun 2023 12:09:27 +0200 Subject: [PATCH 337/364] Swift: Enable implicit this warnings for remaining packs --- swift/downgrades/qlpack.yml | 1 + swift/integration-tests/qlpack.yml | 1 + swift/ql/consistency-queries/qlpack.yml | 1 + swift/ql/examples/qlpack.yml | 1 + 4 files changed, 4 insertions(+) diff --git a/swift/downgrades/qlpack.yml b/swift/downgrades/qlpack.yml index 3fc919124df..3de4eeebc7c 100644 --- a/swift/downgrades/qlpack.yml +++ b/swift/downgrades/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/swift-downgrades groups: swift downgrades: . library: true +warnOnImplicitThis: true diff --git a/swift/integration-tests/qlpack.yml b/swift/integration-tests/qlpack.yml index c0030d14bdf..f0a64418576 100644 --- a/swift/integration-tests/qlpack.yml +++ b/swift/integration-tests/qlpack.yml @@ -4,3 +4,4 @@ dependencies: codeql/swift-all: ${workspace} tests: . extractor: swift +warnOnImplicitThis: true diff --git a/swift/ql/consistency-queries/qlpack.yml b/swift/ql/consistency-queries/qlpack.yml index 57ef2babccf..c1ee319c393 100644 --- a/swift/ql/consistency-queries/qlpack.yml +++ b/swift/ql/consistency-queries/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/swift-consistency-queries groups: [swift, test, consistency-queries] dependencies: codeql/swift-all: ${workspace} +warnOnImplicitThis: true diff --git a/swift/ql/examples/qlpack.yml b/swift/ql/examples/qlpack.yml index ed3c6f12bac..c29a8b7783d 100644 --- a/swift/ql/examples/qlpack.yml +++ b/swift/ql/examples/qlpack.yml @@ -4,3 +4,4 @@ groups: - examples dependencies: codeql/swift-all: ${workspace} +warnOnImplicitThis: true From b4ef2437333f828fceb077491233eb0893139642 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Mon, 26 Jun 2023 12:11:50 +0200 Subject: [PATCH 338/364] Add workflow to check for warnOnImplicitThis --- .github/workflows/check-implicit-this.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/check-implicit-this.yml diff --git a/.github/workflows/check-implicit-this.yml b/.github/workflows/check-implicit-this.yml new file mode 100644 index 00000000000..8539c7b3330 --- /dev/null +++ b/.github/workflows/check-implicit-this.yml @@ -0,0 +1,22 @@ +name: "Check implicit this warnings" + +on: workflow_dispatch + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Check that implicit this warnings is enabled for all packs + shell: bash + run: | + EXIT_CODE=0 + packs="$(find . -iname 'qlpack.yml')" + for pack_file in ${packs}; do + option="$(yq '.warnOnImplicitThis' ${pack_file})" + if [ "${option}" != "true" ]; then + echo "warnOnImplicitThis property must be set to 'true' for pack ${pack_file}" + EXIT_CODE=1 + fi + done + exit "${EXIT_CODE}" From 51176bdff30c2b7dea5e223abc64d4712678fa1e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 27 Jun 2023 12:59:22 +0100 Subject: [PATCH 339/364] C++: Add Geoffrey's testcases. --- .../ConstantSizeArrayOffByOne.expected | 49 +++++++++++++++++++ .../CWE/CWE-193/constant-size/test.cpp | 27 ++++++++++ 2 files changed, 76 insertions(+) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected index 4f5031a0a6e..ff75c77e702 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/ConstantSizeArrayOffByOne.expected @@ -1,41 +1,74 @@ edges +| test.cpp:34:10:34:12 | buf | test.cpp:34:5:34:24 | access to array | | test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array | | test.cpp:36:10:36:12 | buf | test.cpp:36:5:36:24 | access to array | +| test.cpp:39:14:39:16 | buf | test.cpp:39:9:39:19 | access to array | | test.cpp:43:14:43:16 | buf | test.cpp:43:9:43:19 | access to array | +| test.cpp:48:10:48:12 | buf | test.cpp:48:5:48:24 | access to array | | test.cpp:49:10:49:12 | buf | test.cpp:49:5:49:22 | access to array | | test.cpp:50:10:50:12 | buf | test.cpp:50:5:50:24 | access to array | +| test.cpp:53:14:53:16 | buf | test.cpp:53:9:53:19 | access to array | | test.cpp:57:14:57:16 | buf | test.cpp:57:9:57:19 | access to array | | test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array | +| test.cpp:70:33:70:33 | p | test.cpp:71:5:71:17 | access to array | | test.cpp:70:33:70:33 | p | test.cpp:72:5:72:15 | access to array | +| test.cpp:76:26:76:46 | & ... | test.cpp:66:32:66:32 | p | +| test.cpp:76:32:76:34 | buf | test.cpp:76:26:76:46 | & ... | | test.cpp:77:26:77:44 | & ... | test.cpp:66:32:66:32 | p | | test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... | | test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p | | test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf | | test.cpp:85:34:85:36 | buf | test.cpp:87:5:87:31 | access to array | | test.cpp:85:34:85:36 | buf | test.cpp:88:5:88:27 | access to array | +| test.cpp:96:13:96:15 | arr | test.cpp:96:13:96:18 | access to array | +| test.cpp:111:17:111:19 | arr | test.cpp:111:17:111:22 | access to array | +| test.cpp:111:17:111:19 | arr | test.cpp:115:35:115:40 | access to array | +| test.cpp:111:17:111:19 | arr | test.cpp:119:17:119:22 | access to array | +| test.cpp:115:35:115:37 | arr | test.cpp:111:17:111:22 | access to array | +| test.cpp:115:35:115:37 | arr | test.cpp:115:35:115:40 | access to array | +| test.cpp:115:35:115:37 | arr | test.cpp:119:17:119:22 | access to array | +| test.cpp:119:17:119:19 | arr | test.cpp:111:17:111:22 | access to array | +| test.cpp:119:17:119:19 | arr | test.cpp:115:35:115:40 | access to array | +| test.cpp:119:17:119:19 | arr | test.cpp:119:17:119:22 | access to array | | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | | test.cpp:134:25:134:27 | arr | test.cpp:136:9:136:16 | ... += ... | | test.cpp:136:9:136:16 | ... += ... | test.cpp:138:13:138:15 | arr | | test.cpp:143:18:143:21 | asdf | test.cpp:134:25:134:27 | arr | | test.cpp:143:18:143:21 | asdf | test.cpp:143:18:143:21 | asdf | +| test.cpp:148:23:148:28 | buffer | test.cpp:150:5:150:11 | access to array | +| test.cpp:148:23:148:28 | buffer | test.cpp:151:5:151:11 | access to array | +| test.cpp:159:25:159:29 | array | test.cpp:161:5:161:10 | access to array | +| test.cpp:159:25:159:29 | array | test.cpp:162:5:162:10 | access to array | nodes +| test.cpp:34:5:34:24 | access to array | semmle.label | access to array | +| test.cpp:34:10:34:12 | buf | semmle.label | buf | | test.cpp:35:5:35:22 | access to array | semmle.label | access to array | | test.cpp:35:10:35:12 | buf | semmle.label | buf | | test.cpp:36:5:36:24 | access to array | semmle.label | access to array | | test.cpp:36:10:36:12 | buf | semmle.label | buf | +| test.cpp:39:9:39:19 | access to array | semmle.label | access to array | +| test.cpp:39:14:39:16 | buf | semmle.label | buf | | test.cpp:43:9:43:19 | access to array | semmle.label | access to array | | test.cpp:43:14:43:16 | buf | semmle.label | buf | +| test.cpp:48:5:48:24 | access to array | semmle.label | access to array | +| test.cpp:48:10:48:12 | buf | semmle.label | buf | | test.cpp:49:5:49:22 | access to array | semmle.label | access to array | | test.cpp:49:10:49:12 | buf | semmle.label | buf | | test.cpp:50:5:50:24 | access to array | semmle.label | access to array | | test.cpp:50:10:50:12 | buf | semmle.label | buf | +| test.cpp:53:9:53:19 | access to array | semmle.label | access to array | +| test.cpp:53:14:53:16 | buf | semmle.label | buf | | test.cpp:57:9:57:19 | access to array | semmle.label | access to array | | test.cpp:57:14:57:16 | buf | semmle.label | buf | | test.cpp:61:9:61:19 | access to array | semmle.label | access to array | | test.cpp:61:14:61:16 | buf | semmle.label | buf | | test.cpp:66:32:66:32 | p | semmle.label | p | +| test.cpp:66:32:66:32 | p | semmle.label | p | | test.cpp:70:33:70:33 | p | semmle.label | p | +| test.cpp:71:5:71:17 | access to array | semmle.label | access to array | | test.cpp:72:5:72:15 | access to array | semmle.label | access to array | +| test.cpp:76:26:76:46 | & ... | semmle.label | & ... | +| test.cpp:76:32:76:34 | buf | semmle.label | buf | | test.cpp:77:26:77:44 | & ... | semmle.label | & ... | | test.cpp:77:32:77:34 | buf | semmle.label | buf | | test.cpp:79:27:79:34 | buf | semmle.label | buf | @@ -43,6 +76,14 @@ nodes | test.cpp:85:34:85:36 | buf | semmle.label | buf | | test.cpp:87:5:87:31 | access to array | semmle.label | access to array | | test.cpp:88:5:88:27 | access to array | semmle.label | access to array | +| test.cpp:96:13:96:15 | arr | semmle.label | arr | +| test.cpp:96:13:96:18 | access to array | semmle.label | access to array | +| test.cpp:111:17:111:19 | arr | semmle.label | arr | +| test.cpp:111:17:111:22 | access to array | semmle.label | access to array | +| test.cpp:115:35:115:37 | arr | semmle.label | arr | +| test.cpp:115:35:115:40 | access to array | semmle.label | access to array | +| test.cpp:119:17:119:19 | arr | semmle.label | arr | +| test.cpp:119:17:119:22 | access to array | semmle.label | access to array | | test.cpp:128:9:128:11 | arr | semmle.label | arr | | test.cpp:128:9:128:14 | access to array | semmle.label | access to array | | test.cpp:134:25:134:27 | arr | semmle.label | arr | @@ -50,6 +91,12 @@ nodes | test.cpp:138:13:138:15 | arr | semmle.label | arr | | test.cpp:143:18:143:21 | asdf | semmle.label | asdf | | test.cpp:143:18:143:21 | asdf | semmle.label | asdf | +| test.cpp:148:23:148:28 | buffer | semmle.label | buffer | +| test.cpp:150:5:150:11 | access to array | semmle.label | access to array | +| test.cpp:151:5:151:11 | access to array | semmle.label | access to array | +| test.cpp:159:25:159:29 | array | semmle.label | array | +| test.cpp:161:5:161:10 | access to array | semmle.label | access to array | +| test.cpp:162:5:162:10 | access to array | semmle.label | access to array | subpaths #select | test.cpp:35:5:35:22 | PointerAdd: access to array | test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:35:5:35:26 | Store: ... = ... | write | @@ -64,3 +111,5 @@ subpaths | test.cpp:88:5:88:27 | PointerAdd: access to array | test.cpp:85:34:85:36 | buf | test.cpp:88:5:88:27 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:88:5:88:31 | Store: ... = ... | write | | test.cpp:128:9:128:14 | PointerAdd: access to array | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:125:11:125:13 | arr | arr | test.cpp:128:9:128:18 | Store: ... = ... | write | | test.cpp:136:9:136:16 | PointerAdd: ... += ... | test.cpp:143:18:143:21 | asdf | test.cpp:138:13:138:15 | arr | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:142:10:142:13 | asdf | asdf | test.cpp:138:12:138:15 | Load: * ... | read | +| test.cpp:151:5:151:11 | PointerAdd: access to array | test.cpp:148:23:148:28 | buffer | test.cpp:151:5:151:11 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:147:19:147:24 | buffer | buffer | test.cpp:151:5:151:15 | Store: ... = ... | write | +| test.cpp:162:5:162:10 | PointerAdd: access to array | test.cpp:159:25:159:29 | array | test.cpp:162:5:162:10 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:158:10:158:14 | array | array | test.cpp:162:5:162:19 | Store: ... = ... | write | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp index f799518f6ec..902bf5a2cd9 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/constant-size/test.cpp @@ -142,3 +142,30 @@ void testStrncmp1() { char asdf[5]; testStrncmp2(asdf); } + +void pointer_size_larger_than_array_element_size() { + unsigned char buffer[100]; // getByteSize() = 100 + int *ptr = (int *)buffer; // pai.getElementSize() will be sizeof(int) = 4 -> size = 25 + + ptr[24] = 0; // GOOD: writes bytes 96, 97, 98, 99 + ptr[25] = 0; // BAD: writes bytes 100, 101, 102, 103 +} + +struct vec2 { int x, y; }; +struct vec3 { int x, y, z; }; + +void pointer_size_smaller_than_array_element_size_but_does_not_divide_it() { + vec3 array[3]; // getByteSize() = 9 * sizeof(int) + vec2 *ptr = (vec2 *)array; // pai.getElementSize() will be 2 * sizeof(int) -> size = 4 + + ptr[3] = vec2{}; // GOOD: writes ints 6, 7 + ptr[4] = vec2{}; // BAD: writes ints 8, 9 +} + +void pointer_size_larger_than_array_element_size_and_does_not_divide_it() { + vec2 array[2]; // getByteSize() = 4 * sizeof(int) = 4 * 4 = 16 + vec3 *ptr = (vec3 *)array; // pai.getElementSize() will be 3 * sizeof(int) -> size = 1 + + ptr[0] = vec3{}; // GOOD: writes ints 0, 1, 2 + ptr[1] = vec3{}; // BAD: writes ints 3, 4, 5 [NOT DETECTED] +} From d588f522621662ed3574ed09d3438180af393d11 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Tue, 27 Jun 2023 13:33:52 +0100 Subject: [PATCH 340/364] Kotlin: Remove an out-of-date comment --- java/kotlin-extractor/src/main/kotlin/utils/Logger.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt b/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt index 3b66e527429..55624f3c342 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/Logger.kt @@ -204,9 +204,6 @@ open class LoggerBase(val logCounter: LogCounter) { val severity = info.first val count = info.second if(count >= logCounter.diagnosticLimit) { - // We don't know if this location relates to an error - // or a warning, so we just declare hitting the limit - // to be an error regardless. val message = "Total of $count diagnostics (reached limit of ${logCounter.diagnosticLimit}) from $caller." if (verbosity >= 1) { emitDiagnostic(tw, severity, "Limit", message, message) From d1979197c75d2ea2d17f2d5eea41ea7a71719c05 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Tue, 27 Jun 2023 11:20:08 +0200 Subject: [PATCH 341/364] CPP: Enable implicit this warnings for remaining packs --- cpp/downgrades/qlpack.yml | 1 + cpp/ql/examples/qlpack.yml | 1 + .../query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/cpp/downgrades/qlpack.yml b/cpp/downgrades/qlpack.yml index 9155f820e7e..bcaae0a19c9 100644 --- a/cpp/downgrades/qlpack.yml +++ b/cpp/downgrades/qlpack.yml @@ -2,3 +2,4 @@ name: codeql/cpp-downgrades groups: cpp downgrades: . library: true +warnOnImplicitThis: true diff --git a/cpp/ql/examples/qlpack.yml b/cpp/ql/examples/qlpack.yml index d7f3a9634cc..2b92e450a8c 100644 --- a/cpp/ql/examples/qlpack.yml +++ b/cpp/ql/examples/qlpack.yml @@ -4,3 +4,4 @@ groups: - examples dependencies: codeql/cpp-all: ${workspace} +warnOnImplicitThis: true diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml index 096e9d13dd2..d29089ece4d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml @@ -6,3 +6,4 @@ dependencies: codeql/cpp-queries: ${workspace} extractor: cpp tests: . +warnOnImplicitThis: true From 6812389fc87981c9ab7cddb52903973c17335dd2 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 27 Jun 2023 16:31:06 +0200 Subject: [PATCH 342/364] C#: Fix external API name for nested types This fixes the name of reported external APIs for nested types. The `getDeclaringType().getUnboundDeclaration()`'s `toString()` method reports the name of the type, but not the name of the declaring type. This results in missing information in the `UnsupportedExternalAPIs.ql` query. For example, previously it would report: ``` GitHub.Nested#NestedClass.Test() ``` However, the `NestedClass` class does not exist in the namespace and is only a nested type within `MyFirstClass`. The correct name should be: ``` GitHub.Nested#MyFirstClass+NestedClass.Test() ``` This name also matches the format of MaD. --- csharp/ql/src/Telemetry/ExternalApi.qll | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/csharp/ql/src/Telemetry/ExternalApi.qll b/csharp/ql/src/Telemetry/ExternalApi.qll index 9358e9ce8e4..0921bdf7b5c 100644 --- a/csharp/ql/src/Telemetry/ExternalApi.qll +++ b/csharp/ql/src/Telemetry/ExternalApi.qll @@ -50,7 +50,7 @@ class ExternalApi extends DotNet::Callable { bindingset[this] private string getSignature() { result = - this.getDeclaringType().getUnboundDeclaration() + "." + this.getName() + "(" + + nestedName(this.getDeclaringType().getUnboundDeclaration()) + "." + this.getName() + "(" + parameterQualifiedTypeNamesToString(this) + ")" } @@ -118,6 +118,21 @@ class ExternalApi extends DotNet::Callable { } } +/** + * Gets the nested name of the declaration. + * + * If the declaration is not a nested type, the result is the same as \`getName()\`. + * Otherwise the name of the nested type is prefixed with a \`+\` and appended to + * the name of the enclosing type, which might be a nested type as well. + */ +private string nestedName(Declaration declaration) { + not exists(declaration.getDeclaringType().getUnboundDeclaration()) and + result = declaration.getName() + or + nestedName(declaration.getDeclaringType().getUnboundDeclaration()) + "+" + declaration.getName() = + result +} + /** * Gets the limit for the number of results produced by a telemetry query. */ From af41dabc14223e154f708c1f7c01fd05b5fc8419 Mon Sep 17 00:00:00 2001 From: Alex Denisov Date: Mon, 26 Jun 2023 16:13:39 +0200 Subject: [PATCH 343/364] Swift: extend the frontend observer --- swift/extractor/main.cpp | 3 ++- swift/third_party/load.bzl | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/swift/extractor/main.cpp b/swift/extractor/main.cpp index de7fd703161..4f1dd990be9 100644 --- a/swift/extractor/main.cpp +++ b/swift/extractor/main.cpp @@ -85,6 +85,7 @@ class Observer : public swift::FrontendObserver { void parsedArgs(swift::CompilerInvocation& invocation) override { auto& options = invocation.getFrontendOptions(); + options.KeepASTContext = true; lockOutputSwiftModuleTraps(state, options); processFrontendOptions(state, options); } @@ -93,7 +94,7 @@ class Observer : public swift::FrontendObserver { instance.addDiagnosticConsumer(&diagConsumer); } - void performedSemanticAnalysis(swift::CompilerInstance& compiler) override { + void performedCompilation(swift::CompilerInstance& compiler) override { codeql::extractSwiftFiles(state, compiler); codeql::extractSwiftInvocation(state, compiler, invocationTrap); codeql::extractExtractLazyDeclarations(state, compiler); diff --git a/swift/third_party/load.bzl b/swift/third_party/load.bzl index 545ac2b4b95..a046946e573 100644 --- a/swift/third_party/load.bzl +++ b/swift/third_party/load.bzl @@ -4,11 +4,11 @@ load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") # TODO: remove `remove-result-of.patch` once we update to a Swift version containing # https://github.com/apple/swift/commit/2ed2cea2 # (probably when updating to 5.9) -_swift_prebuilt_version = "swift-5.8.1-RELEASE.208" +_swift_prebuilt_version = "swift-5.8.1-RELEASE.210" _swift_sha_map = { - "Linux-X64": "1d93286d6219e5c5746938ab9287d90efea98039f022cb1433296ccbc1684bc0", - "macOS-ARM64": "a29ce5143cb2c68190e337a35ebb163e961a58b9d8826fe7f8daf4d8381ee75d", - "macOS-X64": "a7e63ea732750c783142083df20a34c8d337b9b9ba210fa6a9e5ada7b7880189", + "Linux-X64": "d8c715044c3989683b3f986a377647697245ed6bbdc2add13890433c9dc732a4", + "macOS-ARM64": "2ca169f299bce61034bd011f081a55be07a19f20fd7ea855b241f43fe0fb76d2", + "macOS-X64": "80e2e8cefbd78d71e54923c1da36cac3511b4c69c4841cf35bef383bc6750d18", } _swift_arch_map = { From ea5eda0f2249ff204bee1bdd9ee6b8dd5cbb0b86 Mon Sep 17 00:00:00 2001 From: Alex Denisov Date: Tue, 27 Jun 2023 15:26:59 +0200 Subject: [PATCH 344/364] Swift: adjust test expectations --- .../CONSISTENCY/CfgConsistency.expected | 6 ---- .../CONSISTENCY/CfgConsistency.expected | 2 -- .../CONSISTENCY/CfgConsistency.expected | 6 ---- .../CONSISTENCY/CfgConsistency.expected | 2 -- .../ast/CONSISTENCY/CfgConsistency.expected | 9 ----- .../ql/test/library-tests/ast/Errors.expected | 4 --- .../test/library-tests/ast/PrintAst.expected | 36 ++++++++++++------- .../graph/CONSISTENCY/CfgConsistency.expected | 2 -- .../CONSISTENCY/CfgConsistency.expected | 5 --- .../CONSISTENCY/CfgConsistency.expected | 10 ------ .../CONSISTENCY/CfgConsistency.expected | 3 -- .../CONSISTENCY/CfgConsistency.expected | 2 -- .../CONSISTENCY/CfgConsistency.expected | 11 ------ .../CONSISTENCY/CfgConsistency.expected | 5 --- .../CONSISTENCY/CfgConsistency.expected | 2 -- .../CONSISTENCY/CfgConsistency.expected | 6 ---- .../CONSISTENCY/CfgConsistency.expected | 13 ------- .../CONSISTENCY/CfgConsistency.expected | 9 ----- .../CONSISTENCY/CfgConsistency.expected | 2 -- .../CONSISTENCY/CfgConsistency.expected | 5 --- .../CONSISTENCY/CfgConsistency.expected | 5 --- .../CONSISTENCY/CfgConsistency.expected | 5 --- .../CONSISTENCY/CfgConsistency.expected | 5 --- 23 files changed, 24 insertions(+), 131 deletions(-) delete mode 100644 swift/ql/test/extractor-tests/declarations/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/extractor-tests/expressions/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/extractor-tests/generated/decl/EnumDecl/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/extractor-tests/statements/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/library-tests/dataflow/taint/libraries/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/library-tests/elements/decl/enumdecl/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/library-tests/elements/decl/function/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-089/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-1204/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-259/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-311/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-312/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-321/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-327/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-328/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-611/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-757/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-760/CONSISTENCY/CfgConsistency.expected delete mode 100644 swift/ql/test/query-tests/Security/CWE-916/CONSISTENCY/CfgConsistency.expected diff --git a/swift/ql/test/extractor-tests/declarations/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/extractor-tests/declarations/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 9d02611e7a7..00000000000 --- a/swift/ql/test/extractor-tests/declarations/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,6 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/extractor-tests/expressions/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/extractor-tests/expressions/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 069a6ecbc6a..00000000000 --- a/swift/ql/test/extractor-tests/expressions/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,2 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/extractor-tests/generated/decl/EnumDecl/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/extractor-tests/generated/decl/EnumDecl/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 9d02611e7a7..00000000000 --- a/swift/ql/test/extractor-tests/generated/decl/EnumDecl/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,6 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/extractor-tests/statements/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/extractor-tests/statements/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 069a6ecbc6a..00000000000 --- a/swift/ql/test/extractor-tests/statements/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,2 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/library-tests/ast/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/library-tests/ast/CONSISTENCY/CfgConsistency.expected index fdfaa9f18cd..9c49013832a 100644 --- a/swift/ql/test/library-tests/ast/CONSISTENCY/CfgConsistency.expected +++ b/swift/ql/test/library-tests/ast/CONSISTENCY/CfgConsistency.expected @@ -8,13 +8,4 @@ multipleSuccessors deadEnd | cfg.swift:33:49:33:60 | call to isZero(x:) | | cfg.swift:144:18:144:34 | ... .&&(_:_:) ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | | patterns.swift:16:10:16:14 | =~ ... | diff --git a/swift/ql/test/library-tests/ast/Errors.expected b/swift/ql/test/library-tests/ast/Errors.expected index e289df1fc15..a65eb1b2466 100644 --- a/swift/ql/test/library-tests/ast/Errors.expected +++ b/swift/ql/test/library-tests/ast/Errors.expected @@ -1,5 +1 @@ -| file://:0:0:0:0 | ... .combine(_:) | UnresolvedDotExpr | -| file://:0:0:0:0 | ... .combine(_:) | UnresolvedDotExpr | -| file://:0:0:0:0 | ... .combine(_:) | UnresolvedDotExpr | -| file://:0:0:0:0 | ... .combine(_:) | UnresolvedDotExpr | | patterns.swift:16:12:16:12 | OverloadedDeclRefExpr | OverloadedDeclRefExpr | diff --git a/swift/ql/test/library-tests/ast/PrintAst.expected b/swift/ql/test/library-tests/ast/PrintAst.expected index cb7091193f1..39320293cbc 100644 --- a/swift/ql/test/library-tests/ast/PrintAst.expected +++ b/swift/ql/test/library-tests/ast/PrintAst.expected @@ -2795,11 +2795,14 @@ cfg.swift: #-----| getSource(): [IntegerLiteralExpr] 1 #-----| getLabel(0): [CaseLabelItem] .B #-----| getPattern(): [EnumElementPattern] .B -#-----| getElement(2): [CallExpr] call to ... -#-----| getFunction(): [UnresolvedDotExpr] ... .combine(_:) -#-----| getBase(): [DeclRefExpr] hasher +#-----| getElement(2): [CallExpr] call to combine(_:) +#-----| getFunction(): [MethodLookupExpr] .combine(_:) +#-----| getBase(): [InOutExpr] &... +#-----| getSubExpr(): [DeclRefExpr] hasher +#-----| getMethodRef(): [DeclRefExpr] combine(_:) #-----| getArgument(0): [Argument] : discriminator #-----| getExpr(): [DeclRefExpr] discriminator +#-----| getExpr().getFullyConverted(): [LoadExpr] (Int) ... #-----| getMember(7): [ConcreteVarDecl] hashValue #-----| Type = Int #-----| getAccessor(0): [Accessor] get @@ -3482,11 +3485,14 @@ declarations.swift: #-----| getSource(): [IntegerLiteralExpr] 4 #-----| getLabel(0): [CaseLabelItem] .value5 #-----| getPattern(): [EnumElementPattern] .value5 -#-----| getElement(2): [CallExpr] call to ... -#-----| getFunction(): [UnresolvedDotExpr] ... .combine(_:) -#-----| getBase(): [DeclRefExpr] hasher +#-----| getElement(2): [CallExpr] call to combine(_:) +#-----| getFunction(): [MethodLookupExpr] .combine(_:) +#-----| getBase(): [InOutExpr] &... +#-----| getSubExpr(): [DeclRefExpr] hasher +#-----| getMethodRef(): [DeclRefExpr] combine(_:) #-----| getArgument(0): [Argument] : discriminator #-----| getExpr(): [DeclRefExpr] discriminator +#-----| getExpr().getFullyConverted(): [LoadExpr] (Int) ... #-----| getMember(10): [ConcreteVarDecl] hashValue #-----| Type = Int #-----| getAccessor(0): [Accessor] get @@ -4394,11 +4400,14 @@ expressions.swift: #-----| getSource(): [IntegerLiteralExpr] 0 #-----| getLabel(0): [CaseLabelItem] .failed #-----| getPattern(): [EnumElementPattern] .failed -#-----| getElement(2): [CallExpr] call to ... -#-----| getFunction(): [UnresolvedDotExpr] ... .combine(_:) -#-----| getBase(): [DeclRefExpr] hasher +#-----| getElement(2): [CallExpr] call to combine(_:) +#-----| getFunction(): [MethodLookupExpr] .combine(_:) +#-----| getBase(): [InOutExpr] &... +#-----| getSubExpr(): [DeclRefExpr] hasher +#-----| getMethodRef(): [DeclRefExpr] combine(_:) #-----| getArgument(0): [Argument] : discriminator #-----| getExpr(): [DeclRefExpr] discriminator +#-----| getExpr().getFullyConverted(): [LoadExpr] (Int) ... #-----| getMember(5): [ConcreteVarDecl] hashValue #-----| Type = Int #-----| getAccessor(0): [Accessor] get @@ -6656,11 +6665,14 @@ statements.swift: #-----| getSource(): [IntegerLiteralExpr] 0 #-----| getLabel(0): [CaseLabelItem] .failed #-----| getPattern(): [EnumElementPattern] .failed -#-----| getElement(2): [CallExpr] call to ... -#-----| getFunction(): [UnresolvedDotExpr] ... .combine(_:) -#-----| getBase(): [DeclRefExpr] hasher +#-----| getElement(2): [CallExpr] call to combine(_:) +#-----| getFunction(): [MethodLookupExpr] .combine(_:) +#-----| getBase(): [InOutExpr] &... +#-----| getSubExpr(): [DeclRefExpr] hasher +#-----| getMethodRef(): [DeclRefExpr] combine(_:) #-----| getArgument(0): [Argument] : discriminator #-----| getExpr(): [DeclRefExpr] discriminator +#-----| getExpr().getFullyConverted(): [LoadExpr] (Int) ... #-----| getMember(5): [ConcreteVarDecl] hashValue #-----| Type = Int #-----| getAccessor(0): [Accessor] get diff --git a/swift/ql/test/library-tests/controlflow/graph/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/library-tests/controlflow/graph/CONSISTENCY/CfgConsistency.expected index 0c4047134f3..81ad590aaab 100644 --- a/swift/ql/test/library-tests/controlflow/graph/CONSISTENCY/CfgConsistency.expected +++ b/swift/ql/test/library-tests/controlflow/graph/CONSISTENCY/CfgConsistency.expected @@ -8,5 +8,3 @@ multipleSuccessors deadEnd | cfg.swift:33:49:33:60 | call to isZero(x:) | | cfg.swift:144:18:144:34 | ... .&&(_:_:) ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/library-tests/dataflow/taint/libraries/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/library-tests/dataflow/taint/libraries/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 853828d4f77..00000000000 --- a/swift/ql/test/library-tests/dataflow/taint/libraries/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,5 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/library-tests/elements/decl/enumdecl/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/library-tests/elements/decl/enumdecl/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 4de95c00602..00000000000 --- a/swift/ql/test/library-tests/elements/decl/enumdecl/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,10 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/library-tests/elements/decl/function/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/library-tests/elements/decl/function/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 280e2eeab41..00000000000 --- a/swift/ql/test/library-tests/elements/decl/function/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,3 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-089/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-089/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 069a6ecbc6a..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-089/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,2 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-1204/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-1204/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 90f66c1830d..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-1204/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,11 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-259/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-259/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 853828d4f77..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-259/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,5 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-311/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-311/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 069a6ecbc6a..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-311/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,2 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-312/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-312/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 9d02611e7a7..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-312/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,6 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-321/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-321/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 65cf24d02a7..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-321/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,13 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-327/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-327/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index fc0518030f4..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-327/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,9 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-328/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-328/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 069a6ecbc6a..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-328/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,2 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-611/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-611/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 107533d785d..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-611/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,5 +0,0 @@ -deadEnd -| file://:0:0:0:0 | StmtCondition | -| file://:0:0:0:0 | StmtCondition | -| file://:0:0:0:0 | hasher | -| file://:0:0:0:0 | hasher | diff --git a/swift/ql/test/query-tests/Security/CWE-757/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-757/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 853828d4f77..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-757/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,5 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-760/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-760/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 853828d4f77..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-760/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,5 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | diff --git a/swift/ql/test/query-tests/Security/CWE-916/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/query-tests/Security/CWE-916/CONSISTENCY/CfgConsistency.expected deleted file mode 100644 index 853828d4f77..00000000000 --- a/swift/ql/test/query-tests/Security/CWE-916/CONSISTENCY/CfgConsistency.expected +++ /dev/null @@ -1,5 +0,0 @@ -deadEnd -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | -| file://:0:0:0:0 | ... = ... | From e90153fc471e813cec10661e1a57c57631f37854 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 27 Jun 2023 16:52:45 -0400 Subject: [PATCH 345/364] C++: fix irreducible control flow logic --- .../cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll | 2 +- cpp/ql/test/library-tests/ir/range-analysis/test.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll index 1a5a30d1454..9bc55e4fa80 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll @@ -70,7 +70,7 @@ predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionP // Conservatively assume that every edge is a back edge if we don't have dominance information. ( phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or - irreducibleSccEdge(phi.getBasicBlock(), edge.getOrigBlock()) or + irreducibleSccEdge(edge.getOrigBlock(), phi.getBasicBlock()) or not edge.getOrigBlock().hasDominanceInformation() ) } diff --git a/cpp/ql/test/library-tests/ir/range-analysis/test.cpp b/cpp/ql/test/library-tests/ir/range-analysis/test.cpp index 1e28d858b78..2271953b7ab 100644 --- a/cpp/ql/test/library-tests/ir/range-analysis/test.cpp +++ b/cpp/ql/test/library-tests/ir/range-analysis/test.cpp @@ -90,7 +90,8 @@ void gotoLoop(bool b1, bool b2) { for (j = 0; j < 10; ++j) { + int x; main_decode_loop: } } -} \ No newline at end of file +} From 0749af79d704b31e662977ce4405661fadcc937e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 00:18:40 +0000 Subject: [PATCH 346/364] Add changed framework coverage reports --- java/documentation/library-coverage/coverage.csv | 6 ++++-- java/documentation/library-coverage/coverage.rst | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index 540f282f7c5..02d4c5aa4c8 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -56,8 +56,8 @@ jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,94,55 java.awt,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3 java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, java.io,49,,45,,,22,,,,,,,,,,,,,,27,,,,,,,,,,,,,,,,,,,43,2 -java.lang,18,,92,,,,,,,,,,,,,,8,,,5,,,4,,,1,,,,,,,,,,,,,56,36 -java.net,13,3,20,,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,3,20, +java.lang,31,,92,,13,,,,,,,,,,,,8,,,5,,,4,,,1,,,,,,,,,,,,,56,36 +java.net,13,3,21,,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,3,21, java.nio,47,,35,,,3,,,,,,,,,,,,,,44,,,,,,,,,,,,,,,,,,,35, java.sql,13,,2,,,,,,,,,,,,,,,,,,,,,,,,,,4,,9,,,,,,,,2, java.util,44,,484,,,,,,,,,,,,,,34,,,,,,,5,2,,1,2,,,,,,,,,,,44,440 @@ -90,11 +90,13 @@ org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 org.apache.commons.compress.archivers.tar,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4, +org.apache.commons.exec,6,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, org.apache.commons.httpclient.util,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, org.apache.commons.io,111,,560,,,2,,,,,,,,,,,,,,94,,,,,,,,,15,,,,,,,,,,546,14 org.apache.commons.jelly,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,, org.apache.commons.jexl2,15,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,, org.apache.commons.jexl3,15,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.lang,,,765,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,594,171 org.apache.commons.lang3,6,,424,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,293,131 org.apache.commons.logging,6,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,, org.apache.commons.net,9,12,,,,,,,,,,,,,,,,,,3,,,,,,,,,6,,,,,,,,,12,, diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index dcf4eb2704d..806100ff6d9 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -18,10 +18,10 @@ Java framework & library support `Google Guava `_,``com.google.common.*``,,730,41,7,,,,, JBoss Logging,``org.jboss.logging``,,,324,,,,,, `JSON-java `_,``org.json``,,236,,,,,,, - Java Standard Library,``java.*``,3,682,184,76,,9,,,17 + Java Standard Library,``java.*``,3,683,197,76,,9,,,17 Java extensions,"``javax.*``, ``jakarta.*``",63,611,34,2,4,,1,1,2 Kotlin Standard Library,``kotlin*``,,1847,16,14,,,,,2 `Spring `_,``org.springframework.*``,29,483,115,4,,28,14,,35 - Others,"``antlr``, ``cn.hutool.core.codec``, ``com.alibaba.druid.sql``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.influxdb``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``org.yaml.snakeyaml``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",126,4467,571,89,6,18,18,,200 - Totals,,283,12766,2040,286,16,122,33,1,390 + Others,"``antlr``, ``cn.hutool.core.codec``, ``com.alibaba.druid.sql``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.google.gson``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.thoughtworks.xstream``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.text``, ``groovy.util``, ``hudson``, ``io.jsonwebtoken``, ``io.netty.bootstrap``, ``io.netty.buffer``, ``io.netty.channel``, ``io.netty.handler.codec``, ``io.netty.handler.ssl``, ``io.netty.handler.stream``, ``io.netty.resolver``, ``io.netty.util``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.exec``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.lang``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.cargo.container.installer``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.eclipse.jetty.client``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.hibernate``, ``org.influxdb``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.jooq``, ``org.kohsuke.stapler``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``org.yaml.snakeyaml``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",126,5232,577,89,6,18,18,,200 + Totals,,283,13532,2059,286,16,122,33,1,390 From 6352399645a9be470b96f0f9de5f4231672e59fe Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Mon, 26 Jun 2023 17:06:54 +0200 Subject: [PATCH 347/364] Swift: fix all upstream headers for C++20 --- .pre-commit-config.yaml | 4 ++-- swift/third_party/load.bzl | 9 ++++++- .../add-constructor-to-Compilation.patch | 17 +++++++++++++ .../patches/remove-redundant-operators.patch | 24 +++++++++++++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 swift/third_party/swift-llvm-support/patches/add-constructor-to-Compilation.patch create mode 100644 swift/third_party/swift-llvm-support/patches/remove-redundant-operators.patch diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bb25a64ebfb..2cf6f530354 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,9 +5,9 @@ repos: rev: v3.2.0 hooks: - id: trailing-whitespace - exclude: /test/.*$(? Date: Tue, 27 Jun 2023 09:49:12 +0200 Subject: [PATCH 348/364] Ruby/Python: Use `inline_late` on member predicates --- .../dataflow/new/internal/TypeTracker.qll | 92 ++++++++----------- ruby/ql/lib/codeql/Locations.qll | 19 ++-- .../codeql/ruby/typetracking/TypeTracker.qll | 92 ++++++++----------- 3 files changed, 88 insertions(+), 115 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll index 25521f5f1a5..fb3d7bf828f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll @@ -235,17 +235,6 @@ private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) { step(nodeFrom, _, summary) } -bindingset[nodeFrom, t] -pragma[inline_late] -pragma[noopt] -private TypeTracker stepInlineLate(TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - exists(StepSummary summary | - stepProj(nodeFrom, summary) and - result = t.append(summary) and - step(nodeFrom, nodeTo, summary) - ) -} - private predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) { smallstepNoCall(nodeFrom, nodeTo, summary) or @@ -257,17 +246,6 @@ private predicate smallstepProj(Node nodeFrom, StepSummary summary) { smallstep(nodeFrom, _, summary) } -bindingset[nodeFrom, t] -pragma[inline_late] -pragma[noopt] -private TypeTracker smallstepInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - smallstepProj(nodeFrom, summary) and - result = t.append(summary) and - smallstep(nodeFrom, nodeTo, summary) - ) -} - /** * Holds if `nodeFrom` is being written to the `content` of the object in `nodeTo`. * @@ -501,9 +479,26 @@ class TypeTracker extends TTypeTracker { * Gets the summary that corresponds to having taken a forwards * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. */ - pragma[inline] + bindingset[nodeFrom, this] + pragma[inline_late] + pragma[noopt] TypeTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - result = stepInlineLate(this, nodeFrom, nodeTo) + exists(StepSummary summary | + stepProj(nodeFrom, summary) and + result = this.append(summary) and + step(nodeFrom, nodeTo, summary) + ) + } + + bindingset[nodeFrom, this] + pragma[inline_late] + pragma[noopt] + private TypeTracker smallstepNoSimpleLocalFlowStep(Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + smallstepProj(nodeFrom, summary) and + result = this.append(summary) and + smallstep(nodeFrom, nodeTo, summary) + ) } /** @@ -532,7 +527,7 @@ class TypeTracker extends TTypeTracker { */ pragma[inline] TypeTracker smallstep(Node nodeFrom, Node nodeTo) { - result = smallstepInlineLate(this, nodeFrom, nodeTo) + result = this.smallstepNoSimpleLocalFlowStep(nodeFrom, nodeTo) or simpleLocalFlowStep(nodeFrom, nodeTo) and result = this @@ -552,34 +547,10 @@ private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) { step(_, nodeTo, summary) } -bindingset[nodeTo, t] -pragma[inline_late] -pragma[noopt] -private TypeBackTracker backStepInlineLate( - TypeBackTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo -) { - exists(StepSummary summary | - backStepProj(nodeTo, summary) and - result = t.prepend(summary) and - step(nodeFrom, nodeTo, summary) - ) -} - private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) { smallstep(_, nodeTo, summary) } -bindingset[nodeTo, t] -pragma[inline_late] -pragma[noopt] -private TypeBackTracker backSmallstepInlineLate(TypeBackTracker t, Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - backSmallstepProj(nodeTo, summary) and - result = t.prepend(summary) and - smallstep(nodeFrom, nodeTo, summary) - ) -} - /** * A summary of the steps needed to back-track a use of a value to a given dataflow node. * @@ -661,9 +632,26 @@ class TypeBackTracker extends TTypeBackTracker { * Gets the summary that corresponds to having taken a backwards * heap and/or inter-procedural step from `nodeTo` to `nodeFrom`. */ - pragma[inline] + bindingset[nodeTo, result] + pragma[inline_late] + pragma[noopt] TypeBackTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - this = backStepInlineLate(result, nodeFrom, nodeTo) + exists(StepSummary summary | + backStepProj(nodeTo, summary) and + this = result.prepend(summary) and + step(nodeFrom, nodeTo, summary) + ) + } + + bindingset[nodeTo, result] + pragma[inline_late] + pragma[noopt] + private TypeBackTracker smallstepNoSimpleLocalFlowStep(Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + backSmallstepProj(nodeTo, summary) and + this = result.prepend(summary) and + smallstep(nodeFrom, nodeTo, summary) + ) } /** @@ -692,7 +680,7 @@ class TypeBackTracker extends TTypeBackTracker { */ pragma[inline] TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) { - this = backSmallstepInlineLate(result, nodeFrom, nodeTo) + this = this.smallstepNoSimpleLocalFlowStep(nodeFrom, nodeTo) or simpleLocalFlowStep(nodeFrom, nodeTo) and this = result diff --git a/ruby/ql/lib/codeql/Locations.qll b/ruby/ql/lib/codeql/Locations.qll index 3a16bdec40d..87198146d88 100644 --- a/ruby/ql/lib/codeql/Locations.qll +++ b/ruby/ql/lib/codeql/Locations.qll @@ -2,15 +2,6 @@ import files.FileSystem -bindingset[loc] -pragma[inline_late] -private string locationToString(Location loc) { - exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | - loc.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and - result = filepath + "@" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn - ) -} - /** * A location as given by a file, a start line, a start column, * an end line, and an end column. @@ -37,8 +28,14 @@ class Location extends @location_default { int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 } /** Gets a textual representation of this element. */ - pragma[inline] - string toString() { result = locationToString(this) } + bindingset[this] + pragma[inline_late] + string toString() { + exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | + this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and + result = filepath + "@" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn + ) + } /** * Holds if this element is at the specified location. diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll index 25521f5f1a5..fb3d7bf828f 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll @@ -235,17 +235,6 @@ private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) { step(nodeFrom, _, summary) } -bindingset[nodeFrom, t] -pragma[inline_late] -pragma[noopt] -private TypeTracker stepInlineLate(TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - exists(StepSummary summary | - stepProj(nodeFrom, summary) and - result = t.append(summary) and - step(nodeFrom, nodeTo, summary) - ) -} - private predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) { smallstepNoCall(nodeFrom, nodeTo, summary) or @@ -257,17 +246,6 @@ private predicate smallstepProj(Node nodeFrom, StepSummary summary) { smallstep(nodeFrom, _, summary) } -bindingset[nodeFrom, t] -pragma[inline_late] -pragma[noopt] -private TypeTracker smallstepInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - smallstepProj(nodeFrom, summary) and - result = t.append(summary) and - smallstep(nodeFrom, nodeTo, summary) - ) -} - /** * Holds if `nodeFrom` is being written to the `content` of the object in `nodeTo`. * @@ -501,9 +479,26 @@ class TypeTracker extends TTypeTracker { * Gets the summary that corresponds to having taken a forwards * heap and/or inter-procedural step from `nodeFrom` to `nodeTo`. */ - pragma[inline] + bindingset[nodeFrom, this] + pragma[inline_late] + pragma[noopt] TypeTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - result = stepInlineLate(this, nodeFrom, nodeTo) + exists(StepSummary summary | + stepProj(nodeFrom, summary) and + result = this.append(summary) and + step(nodeFrom, nodeTo, summary) + ) + } + + bindingset[nodeFrom, this] + pragma[inline_late] + pragma[noopt] + private TypeTracker smallstepNoSimpleLocalFlowStep(Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + smallstepProj(nodeFrom, summary) and + result = this.append(summary) and + smallstep(nodeFrom, nodeTo, summary) + ) } /** @@ -532,7 +527,7 @@ class TypeTracker extends TTypeTracker { */ pragma[inline] TypeTracker smallstep(Node nodeFrom, Node nodeTo) { - result = smallstepInlineLate(this, nodeFrom, nodeTo) + result = this.smallstepNoSimpleLocalFlowStep(nodeFrom, nodeTo) or simpleLocalFlowStep(nodeFrom, nodeTo) and result = this @@ -552,34 +547,10 @@ private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) { step(_, nodeTo, summary) } -bindingset[nodeTo, t] -pragma[inline_late] -pragma[noopt] -private TypeBackTracker backStepInlineLate( - TypeBackTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo -) { - exists(StepSummary summary | - backStepProj(nodeTo, summary) and - result = t.prepend(summary) and - step(nodeFrom, nodeTo, summary) - ) -} - private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) { smallstep(_, nodeTo, summary) } -bindingset[nodeTo, t] -pragma[inline_late] -pragma[noopt] -private TypeBackTracker backSmallstepInlineLate(TypeBackTracker t, Node nodeFrom, Node nodeTo) { - exists(StepSummary summary | - backSmallstepProj(nodeTo, summary) and - result = t.prepend(summary) and - smallstep(nodeFrom, nodeTo, summary) - ) -} - /** * A summary of the steps needed to back-track a use of a value to a given dataflow node. * @@ -661,9 +632,26 @@ class TypeBackTracker extends TTypeBackTracker { * Gets the summary that corresponds to having taken a backwards * heap and/or inter-procedural step from `nodeTo` to `nodeFrom`. */ - pragma[inline] + bindingset[nodeTo, result] + pragma[inline_late] + pragma[noopt] TypeBackTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) { - this = backStepInlineLate(result, nodeFrom, nodeTo) + exists(StepSummary summary | + backStepProj(nodeTo, summary) and + this = result.prepend(summary) and + step(nodeFrom, nodeTo, summary) + ) + } + + bindingset[nodeTo, result] + pragma[inline_late] + pragma[noopt] + private TypeBackTracker smallstepNoSimpleLocalFlowStep(Node nodeFrom, Node nodeTo) { + exists(StepSummary summary | + backSmallstepProj(nodeTo, summary) and + this = result.prepend(summary) and + smallstep(nodeFrom, nodeTo, summary) + ) } /** @@ -692,7 +680,7 @@ class TypeBackTracker extends TTypeBackTracker { */ pragma[inline] TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) { - this = backSmallstepInlineLate(result, nodeFrom, nodeTo) + this = this.smallstepNoSimpleLocalFlowStep(nodeFrom, nodeTo) or simpleLocalFlowStep(nodeFrom, nodeTo) and this = result From e4d2c51ff86334dd8206dc730b52c41eb754db03 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 28 Jun 2023 09:40:31 +0200 Subject: [PATCH 349/364] C#: Add tests for names of nested classes --- .../Telemetry/LibraryUsage/ExternalLibraryUsage.cs | 6 ++++++ .../Telemetry/LibraryUsage/ExternalLibraryUsage.expected | 2 +- .../Telemetry/LibraryUsage/SupportedExternalTaint.expected | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/csharp/ql/test/query-tests/Telemetry/LibraryUsage/ExternalLibraryUsage.cs b/csharp/ql/test/query-tests/Telemetry/LibraryUsage/ExternalLibraryUsage.cs index aaef1776cd3..1ec45beac39 100644 --- a/csharp/ql/test/query-tests/Telemetry/LibraryUsage/ExternalLibraryUsage.cs +++ b/csharp/ql/test/query-tests/Telemetry/LibraryUsage/ExternalLibraryUsage.cs @@ -25,4 +25,10 @@ public class LibraryUsage { var guid1 = Guid.Parse("{12345678-1234-1234-1234-123456789012}"); // Has no flow summary } + + public void M4() + { + var d = new Dictionary(); // Uninteresting parameterless constructor + var e = d.Keys.GetEnumerator().MoveNext(); // Methods on nested classes + } } diff --git a/csharp/ql/test/query-tests/Telemetry/LibraryUsage/ExternalLibraryUsage.expected b/csharp/ql/test/query-tests/Telemetry/LibraryUsage/ExternalLibraryUsage.expected index 7b5c4c57661..54f3920572e 100644 --- a/csharp/ql/test/query-tests/Telemetry/LibraryUsage/ExternalLibraryUsage.expected +++ b/csharp/ql/test/query-tests/Telemetry/LibraryUsage/ExternalLibraryUsage.expected @@ -1,2 +1,2 @@ | System | 5 | -| System.Collections.Generic | 2 | +| System.Collections.Generic | 5 | diff --git a/csharp/ql/test/query-tests/Telemetry/LibraryUsage/SupportedExternalTaint.expected b/csharp/ql/test/query-tests/Telemetry/LibraryUsage/SupportedExternalTaint.expected index b386e4acb38..c9f63591888 100644 --- a/csharp/ql/test/query-tests/Telemetry/LibraryUsage/SupportedExternalTaint.expected +++ b/csharp/ql/test/query-tests/Telemetry/LibraryUsage/SupportedExternalTaint.expected @@ -1 +1,3 @@ | System.Collections.Generic#List<>.Add(T) | 2 | +| System.Collections.Generic#Dictionary<,>+KeyCollection.GetEnumerator() | 1 | +| System.Collections.Generic#Dictionary<,>.get_Keys() | 1 | From 78f2fe8d5e3763776c737a1b682afeff374f0393 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 28 Jun 2023 10:13:03 +0100 Subject: [PATCH 350/364] C++: Fix join in 'argumentOf'. Before: ``` [2023-06-28 09:29:51] Evaluated non-recursive predicate DataFlowImplCommon#59e7a193::Cached::argumentNode#3#fff@8606bd35 in 1945ms (size: 1366058). Evaluated relational algebra for predicate DataFlowImplCommon#59e7a193::Cached::argumentNode#3#fff@8606bd35 with tuple counts: 764401 ~0% {3} r1 = JOIN DataFlowPrivate#fbdd7bd7::DirectPosition#ff_10#join_rhs WITH Instruction#577b6a83::CallInstruction::getArgumentOperand#fff_102#join_rhs ON FIRST 1 OUTPUT Rhs.2, Lhs.1, Rhs.1 764401 ~0% {3} r2 = JOIN r1 WITH DataFlowPrivate#fbdd7bd7::PrimaryArgumentNode#fff_20#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.2, Lhs.1 65 ~0% {3} r3 = SCAN DataFlowPrivate#fbdd7bd7::IndirectionPosition#fff OUTPUT In.2, In.0, In.1 180518864 ~0% {3} r4 = JOIN r3 WITH project#DataFlowPrivate#fbdd7bd7::IndirectOperands::IndirectOperand::hasOperandAndIndirectionIndex#2#dispred#fff#3_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.2, Lhs.1 601657 ~1% {2} r5 = JOIN r4 WITH project#DataFlowUtil#47741e1f::SideEffectOperandNode#fff#2 ON FIRST 2 OUTPUT Lhs.0, Lhs.2 601657 ~0% {3} r6 = JOIN r5 WITH project#DataFlowUtil#47741e1f::SideEffectOperandNode#fff#3 ON FIRST 1 OUTPUT Lhs.0, Rhs.1, Lhs.1 1366058 ~0% {3} r7 = r2 UNION r6 return r7 ``` After: ``` Tuple counts for DataFlowImplCommon#59e7a193::Cached::argumentNode#3#fff/3@d2b091vc after 1.1s: 764381 ~2% {3} r1 = JOIN DataFlowPrivate#fbdd7bd7::DirectPosition#ff_10#join_rhs WITH Instruction#577b6a83::CallInstruction::getArgumentOperand#fff_102#join_rhs ON FIRST 1 OUTPUT Rhs.2, Lhs.1 'pos', Rhs.1 'call' 764381 ~0% {3} r2 = JOIN r1 WITH DataFlowPrivate#fbdd7bd7::PrimaryArgumentNode#fff_20#join_rhs ON FIRST 1 OUTPUT Rhs.1 'n', Lhs.2 'call', Lhs.1 'pos' 65 ~3% {3} r3 = SCAN num#DataFlowPrivate#fbdd7bd7::TIndirectionPosition#fff OUTPUT In.0, In.2 'pos', In.1 1798930 ~1% {3} r4 = JOIN r3 WITH project#DataFlowUtil#47741e1f::SideEffectOperandNode#fff#2_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'n', Lhs.2, Lhs.1 'pos' 601641 ~1% {2} r5 = JOIN r4 WITH project#DataFlowPrivate#fbdd7bd7::IndirectOperands::IndirectOperand::hasOperandAndIndirectionIndex#2#dispred#fff#3 ON FIRST 2 OUTPUT Lhs.0 'n', Lhs.2 'pos' 601641 ~0% {3} r6 = JOIN r5 WITH project#DataFlowUtil#47741e1f::SideEffectOperandNode#fff#3 ON FIRST 1 OUTPUT Lhs.0 'n', Rhs.1 'call', Lhs.1 'pos' 1366022 ~1% {3} r7 = r2 UNION r6 return r7 ``` --- .../code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 31915a888ac..59dfe5ed9d4 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -321,9 +321,11 @@ private class PrimaryArgumentNode extends ArgumentNode, OperandNode { private class SideEffectArgumentNode extends ArgumentNode, SideEffectOperandNode { override predicate argumentOf(DataFlowCall dfCall, ArgumentPosition pos) { - this.getCallInstruction() = dfCall and - pos.(IndirectionPosition).getArgumentIndex() = this.getArgumentIndex() and - super.hasAddressOperandAndIndirectionIndex(_, pos.(IndirectionPosition).getIndirectionIndex()) + exists(int indirectionIndex | + pos = TIndirectionPosition(argumentIndex, pragma[only_bind_into](indirectionIndex)) and + this.getCallInstruction() = dfCall and + super.hasAddressOperandAndIndirectionIndex(_, pragma[only_bind_into](indirectionIndex)) + ) } } From dbdd6544652b83aab4168c457292c56490f25bd5 Mon Sep 17 00:00:00 2001 From: Alex Denisov Date: Wed, 28 Jun 2023 12:11:17 +0200 Subject: [PATCH 351/364] Swift: bump Swift build, NFC --- swift/third_party/load.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/swift/third_party/load.bzl b/swift/third_party/load.bzl index 4bceff6ec7a..9cefc77948d 100644 --- a/swift/third_party/load.bzl +++ b/swift/third_party/load.bzl @@ -4,11 +4,11 @@ load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") # TODO: remove `remove-result-of.patch` once we update to a Swift version containing # https://github.com/apple/swift/commit/2ed2cea2 # (probably when updating to 5.9) -_swift_prebuilt_version = "swift-5.8.1-RELEASE.210" +_swift_prebuilt_version = "swift-5.8.1-RELEASE.212" _swift_sha_map = { - "Linux-X64": "d8c715044c3989683b3f986a377647697245ed6bbdc2add13890433c9dc732a4", - "macOS-ARM64": "2ca169f299bce61034bd011f081a55be07a19f20fd7ea855b241f43fe0fb76d2", - "macOS-X64": "80e2e8cefbd78d71e54923c1da36cac3511b4c69c4841cf35bef383bc6750d18", + "Linux-X64": "3e902cc9dbf02129f6bcac84902524a235df0e36d30f3ac54e642b64d3f95a2b", + "macOS-ARM64": "4d93f326bd8a41c89bcf593676407fab2dd84b665f6bfb7ab667a9673084bcda", + "macOS-X64": "988cd193a0590abd282d8d8f3ec2489583d3d2b34162a4e91208fb91e5fb5981", } _swift_arch_map = { From 174ab25867cec523db8a2b642fffd45922519ffa Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Jun 2023 10:58:10 +0200 Subject: [PATCH 352/364] Ruby: address some review comments --- ruby/ql/lib/codeql/ruby/ApiGraphs.qll | 9 ++++----- .../lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll | 5 ++--- ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll | 2 +- ruby/ql/lib/codeql/ruby/typetracking/ApiGraphShared.qll | 1 - 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll index 2dd070ee0df..b643a022014 100644 --- a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll +++ b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll @@ -1,6 +1,6 @@ /** * Provides an implementation of _API graphs_, which allow efficient modelling of how a given - * value is used the code base or how values produced by the code base are consumed by a library. + * value is used by the code base or how values produced by the code base are consumed by a library. * * See `API::Node` for more details. */ @@ -53,7 +53,7 @@ module API { * * The members predicates on this class generally take inheritance and data flow into account. * - * The following example demonstrate a case where data flow was used to find the sink `x`: + * The following example demonstrates a case where data flow was used to find the sink `x`: * ```ruby * def doSomething f * f.bar(x) # API::getTopLevelMember("Foo").getInstance().getMethod("bar").getArgument(0).asSink() @@ -280,7 +280,6 @@ module API { /** * Gets an access to the constant `m` with this value as the base of the access. * - * For example, the constant `A::B` would be found by `API::getATopLevelMember("A").getMember("B")` * For example: * ```ruby * A::B # API::getATopLevelMember("A").getMember("B") @@ -761,7 +760,7 @@ module API { /** * A node corresponding to an argument, right-hand side of a store, or return value from a callable. * - * Such a node may serve as the starting-point of backtracking, and has epsilon edges going + * Such a node may serve as the starting-point of backtracking, and has epsilon edges going to * the backward nodes corresponding to `getALocalSource`. */ private class SinkNode extends Node, Impl::MkSinkNode { @@ -905,7 +904,7 @@ module API { } /** - * Holds if the epsilon `pred -> succ` be generated, to associate `mod` with its references in the codebase. + * Holds if the epsilon `pred -> succ` should be generated, to associate `mod` with its references in the codebase. */ bindingset[mod] pragma[inline_late] diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll index d6fcc1ddf13..d2fb1354798 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll @@ -419,7 +419,7 @@ private module Cached { } /** - * Gets a module for which this constant is the reference to an ancestor module. + * Gets a module for which `constRef` is the reference to an ancestor module. * * For example, `M` is the ancestry target of `C` in the following examples: * ```rb @@ -437,11 +437,10 @@ private module Cached { private ModuleNode getAncestryTarget(ConstRef constRef) { result.getAnAncestorExpr() = constRef } /** - * Gets a scope in which a constant lookup may access the contents of the module referenced by this constant. + * Gets a scope in which a constant lookup may access the contents of the module referenced by `constRef`. */ cached TConstLookupScope getATargetScope(ConstRef constRef) { - forceCachingInSameStage() and result = MkAncestorLookup(getAncestryTarget(constRef).getAnImmediateDescendent*()) or constRef.asConstantAccess() = any(ConstantAccess ac).getScopeExpr() and diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll index f9c15a4c211..4a5d342eeba 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll @@ -128,7 +128,7 @@ class ActiveRecordModelClass extends ClassDeclaration { ) } - /** Gets the class as a `DataFlow::ClasNode`. */ + /** Gets the class as a `DataFlow::ClassNode`. */ DataFlow::ClassNode getClassNode() { result = cls } } diff --git a/ruby/ql/lib/codeql/ruby/typetracking/ApiGraphShared.qll b/ruby/ql/lib/codeql/ruby/typetracking/ApiGraphShared.qll index e27384b1c7b..07b10cb1303 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/ApiGraphShared.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/ApiGraphShared.qll @@ -84,7 +84,6 @@ module ApiGraphShared { pragma[noopt] cached predicate epsilonEdge(ApiNode pred, ApiNode succ) { - // forward exists( StepSummary summary, TypeTrackingNode predNode, TypeTracker predState, TypeTrackingNode succNode, TypeTracker succState From 67032b5d733d8f863772bbbdba98aae493237af3 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Jun 2023 11:01:06 +0200 Subject: [PATCH 353/364] Ruby: add test for self.class call --- .../dataflow/api-graphs/self-dot-class.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 ruby/ql/test/library-tests/dataflow/api-graphs/self-dot-class.rb diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/self-dot-class.rb b/ruby/ql/test/library-tests/dataflow/api-graphs/self-dot-class.rb new file mode 100644 index 00000000000..178cacbe2c0 --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/api-graphs/self-dot-class.rb @@ -0,0 +1,10 @@ +module SelfDotClass + module Mixin + def foo + self.class.bar # $ call=Member[Foo].Method[bar] + end + end + class Subclass < Foo + include Mixin + end +end From f171c21002094891a57ba4b44a25bac340928e50 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Jun 2023 11:44:51 +0200 Subject: [PATCH 354/364] Ruby: remove forwarder for getADescendentModule --- .../codeql/ruby/dataflow/internal/DataFlowPublic.qll | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll index d2fb1354798..7772e5235d7 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll @@ -1518,14 +1518,9 @@ class ConstRef extends LocalSourceNode { * end * ``` */ - pragma[inline] - ModuleNode getADescendentModule() { result = getADescendentModuleInline(this) } -} - -bindingset[ref] -pragma[inline_late] -private ModuleNode getADescendentModuleInline(ConstRef ref) { - MkAncestorLookup(result) = getATargetScope(ref) + bindingset[this] + pragma[inline_late] + ModuleNode getADescendentModule() { MkAncestorLookup(result) = getATargetScope(this) } } /** From 6feda75dd66257f26eb22945afe54a7cca8db39a Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Jun 2023 11:44:59 +0200 Subject: [PATCH 355/364] Ruby: preserve comment in SQLite3 --- ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll index 208bff8d8c9..dfb93a0e6e5 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll @@ -22,6 +22,7 @@ module Sqlite3 { private API::Node dbInstance() { result = databaseConst().getInstance() or + // e.g. SQLite3::Database.new("foo.db") |db| { db.some_method } result = databaseConst().getMethod("new").getBlock().getParameter(0) } From dd868437ce49792f84f311823b3cd546cb38569e Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Jun 2023 11:44:29 +0200 Subject: [PATCH 356/364] Ruby: add asCallable() --- ruby/ql/lib/codeql/ruby/ApiGraphs.qll | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll index b643a022014..0d6e669b1de 100644 --- a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll +++ b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll @@ -200,6 +200,25 @@ module API { pragma[inline_late] DataFlow::Node asSink() { result = asSinkInline(this) } + /** + * Gets a callable that can reach this sink. + * + * For example: + * ```ruby + * Foo.bar do |x| # API::getTopLevelMember("Foo").getMethod("bar").getBlock().asCallable() + * end + * + * class Baz + * def m # API::getTopLevelMember("Foo").getMethod("bar").getArgument(0).getMethod("m").asCallable() + * end + * end + * Foo.bar(Baz.new) + * ``` + */ + bindingset[this] + pragma[inline_late] + DataFlow::CallableNode asCallable() { Impl::asCallable(this.getAnEpsilonSuccessor(), result) } + /** * Get a data-flow node that transitively flows to this value, provided that this value corresponds * to a sink. @@ -1196,6 +1215,11 @@ module API { ) } + cached + predicate asCallable(Node apiNode, DataFlow::CallableNode callable) { + apiNode = getBackwardStartNode(callable) + } + cached predicate contentEdge(Node pred, DataFlow::Content content, Node succ) { exists( From 423da55fb9e79b8ee71ff41db0b9638377e75ec2 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Jun 2023 11:47:15 +0200 Subject: [PATCH 357/364] Ruby: use asCallable() in Twirp model --- ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll index a315ae100ce..eec7ce30e24 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll @@ -21,16 +21,17 @@ module Twirp { this = API::getTopLevelMember("Twirp").getMember("Service").getAnInstantiation() } - private DataFlow::ClassNode getAHandlerClass() { - result.getAnImmediateReference().getAMethodCall("new").flowsTo(this.getArgument(0)) - } - /** * Gets a handler's method. */ - Ast::Method getAHandlerMethod() { - result = this.getAHandlerClass().getAnAncestor().getAnOwnInstanceMethod().asCallableAstNode() + DataFlow::MethodNode getAHandlerMethodNode() { + result = this.getArgument(0).backtrack().getMethod(_).asCallable() } + + /** + * Gets a handler's method as an AST node. + */ + Ast::Method getAHandlerMethod() { result = this.getAHandlerMethodNode().asCallableAstNode() } } /** @@ -52,7 +53,7 @@ module Twirp { DataFlow::ParameterNode { UnmarshaledParameter() { - exists(ServiceInstantiation i | i.getAHandlerMethod().getParameter(0) = this.asParameter()) + this = any(ServiceInstantiation i).getAHandlerMethodNode().getParameter(0) } override string getSourceType() { result = "Twirp Unmarhaled Parameter" } From 129e6349f7498589b10e5e4bedac97f8cddcdb43 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Jun 2023 11:47:46 +0200 Subject: [PATCH 358/364] Ruby: expand Twirp test --- .../library-tests/frameworks/Twirp/Twirp.expected | 2 ++ .../frameworks/Twirp/hello_world_server.rb | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.expected b/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.expected index 66da43ab78b..4f1b0c30920 100644 --- a/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.expected +++ b/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.expected @@ -1,6 +1,8 @@ sourceTest | hello_world_server.rb:8:13:8:15 | req | +| hello_world_server.rb:32:18:32:20 | req | ssrfSinkTest | hello_world_client.rb:6:47:6:75 | "http://localhost:8080/twirp" | serviceInstantiationTest | hello_world_server.rb:24:11:24:61 | call to new | +| hello_world_server.rb:38:1:38:57 | call to new | diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/hello_world_server.rb b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world_server.rb index 1aa0b9aa8de..7cd117a5843 100644 --- a/ruby/ql/test/library-tests/frameworks/Twirp/hello_world_server.rb +++ b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world_server.rb @@ -5,7 +5,7 @@ require_relative 'hello_world/service_twirp.rb' class HelloWorldHandler # test: request - def hello(req, env) + def hello(req, env) puts ">> Hello #{req.name}" {message: "Hello #{req.name}"} end @@ -13,7 +13,7 @@ end class FakeHelloWorldHandler # test: !request - def hello(req, env) + def hello(req, env) puts ">> Hello #{req.name}" {message: "Hello #{req.name}"} end @@ -21,9 +21,18 @@ end handler = HelloWorldHandler.new() # test: serviceInstantiation -service = Example::HelloWorld::HelloWorldService.new(handler) +service = Example::HelloWorld::HelloWorldService.new(handler) path_prefix = "/twirp/" + service.full_name server = WEBrick::HTTPServer.new(Port: 8080) server.mount path_prefix, Rack::Handler::WEBrick, service server.start + +class StaticHandler + def self.hello(req, env) + puts ">> Hello #{req.name}" + {message: "Hello #{req.name}"} + end +end + +Example::HelloWorld::HelloWorldService.new(StaticHandler) From 7af3d226c9a884fc1a93383a50e2217d42e2e80d Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Jun 2023 12:55:05 +0200 Subject: [PATCH 359/364] Ruby: simplify Twirp model --- ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll | 18 ++++++++++++++---- .../library-tests/frameworks/Twirp/Twirp.ql | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll index eec7ce30e24..7b8648bd2b1 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll @@ -16,7 +16,7 @@ module Twirp { /** * A Twirp service instantiation */ - class ServiceInstantiation extends DataFlow::CallNode { + deprecated class ServiceInstantiation extends DataFlow::CallNode { ServiceInstantiation() { this = API::getTopLevelMember("Twirp").getMember("Service").getAnInstantiation() } @@ -37,7 +37,7 @@ module Twirp { /** * A Twirp client */ - class ClientInstantiation extends DataFlow::CallNode { + deprecated class ClientInstantiation extends DataFlow::CallNode { ClientInstantiation() { this = API::getTopLevelMember("Twirp").getMember("Client").getAnInstantiation() } @@ -45,7 +45,10 @@ module Twirp { /** The URL of a Twirp service, considered as a sink. */ class ServiceUrlAsSsrfSink extends ServerSideRequestForgery::Sink { - ServiceUrlAsSsrfSink() { exists(ClientInstantiation c | c.getArgument(0) = this) } + ServiceUrlAsSsrfSink() { + this = + API::getTopLevelMember("Twirp").getMember("Client").getMethod("new").getArgument(0).asSink() + } } /** A parameter that will receive parts of the url when handling an incoming request. */ @@ -53,7 +56,14 @@ module Twirp { DataFlow::ParameterNode { UnmarshaledParameter() { - this = any(ServiceInstantiation i).getAHandlerMethodNode().getParameter(0) + this = + API::getTopLevelMember("Twirp") + .getMember("Service") + .getMethod("new") + .getArgument(0) + .getMethod(_) + .getParameter(0) + .asSource() } override string getSourceType() { result = "Twirp Unmarhaled Parameter" } diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql b/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql index 4c0494f9100..fee49cbb48c 100644 --- a/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql +++ b/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql @@ -5,4 +5,4 @@ query predicate sourceTest(Twirp::UnmarshaledParameter source) { any() } query predicate ssrfSinkTest(Twirp::ServiceUrlAsSsrfSink sink) { any() } -query predicate serviceInstantiationTest(Twirp::ServiceInstantiation si) { any() } +deprecated query predicate serviceInstantiationTest(Twirp::ServiceInstantiation si) { any() } From 2f1223426a40427368e9ac08c914575e208b6812 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Jun 2023 13:36:47 +0200 Subject: [PATCH 360/364] Ruby: add change note --- ruby/ql/lib/change-notes/2023-06-28-tracking-on-demand.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 ruby/ql/lib/change-notes/2023-06-28-tracking-on-demand.md diff --git a/ruby/ql/lib/change-notes/2023-06-28-tracking-on-demand.md b/ruby/ql/lib/change-notes/2023-06-28-tracking-on-demand.md new file mode 100644 index 00000000000..37740acd9ee --- /dev/null +++ b/ruby/ql/lib/change-notes/2023-06-28-tracking-on-demand.md @@ -0,0 +1,7 @@ +--- +category: library +--- +* The API graph library (`codeql.ruby.ApiGraphs`) has been significantly improved, with better support for inheritance, + and data-flow nodes can now be converted to API nodes by calling `.track()` or `.backtrack()` on the node. + API graphs allow for efficient modelling of how a given value is used by the code base, or how values produced by the code base + are consumed by a library. See the documentation for `API::Node` for details and examples. From 39789d4050a5b0f4f8be0c84935d0a2cc66dcc7c Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 28 Jun 2023 13:42:05 +0200 Subject: [PATCH 361/364] Ruby: use a valid change note category --- ruby/ql/lib/change-notes/2023-06-28-tracking-on-demand.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/ql/lib/change-notes/2023-06-28-tracking-on-demand.md b/ruby/ql/lib/change-notes/2023-06-28-tracking-on-demand.md index 37740acd9ee..5aa79d5e2f3 100644 --- a/ruby/ql/lib/change-notes/2023-06-28-tracking-on-demand.md +++ b/ruby/ql/lib/change-notes/2023-06-28-tracking-on-demand.md @@ -1,5 +1,5 @@ --- -category: library +category: majorAnalysis --- * The API graph library (`codeql.ruby.ApiGraphs`) has been significantly improved, with better support for inheritance, and data-flow nodes can now be converted to API nodes by calling `.track()` or `.backtrack()` on the node. From 14609a97954b4151c41132777e69c1f52a766485 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 27 Jun 2023 19:48:42 +0200 Subject: [PATCH 362/364] C++: Add barrier to `InvalidPointerToDerefConfig` in `cpp/invalid-pointer-deref` --- .../CWE/CWE-193/InvalidPointerDeref.ql | 66 ++- .../InvalidPointerDeref.expected | 539 ++++++++++++++---- .../CWE/CWE-193/pointer-deref/test.cpp | 127 ++++- 3 files changed, 599 insertions(+), 133 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql index 6659b820659..c1f7e735636 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql @@ -312,11 +312,13 @@ Instruction getASuccessor(Instruction instr) { */ pragma[inline] predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation, int delta) { - exists(AddressOperand addr, Instruction s | + exists(AddressOperand addr, Instruction s, IRBlock b | s = sink.asInstruction() and - bounded1(addr.getDef(), s, delta) and + boundedImpl(addr.getDef(), s, delta) and delta >= 0 and - i.getAnOperand() = addr + i.getAnOperand() = addr and + b = i.getBlock() and + not b = InvalidPointerToDerefBarrier::getABarrierBlock(delta) | i instanceof StoreInstruction and operation = "write" @@ -326,6 +328,60 @@ predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string o ) } +module InvalidPointerToDerefBarrier { + private module BarrierConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + // The sources is the same as in the sources for `InvalidPointerToDerefConfig`. + invalidPointerToDerefSource(_, source, _) + } + + additional predicate isSink( + DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int state, boolean testIsTrue + ) { + // The sink is any "large" side of a relational comparison. + g.comparesLt(left.asOperand(), right.asOperand(), state, true, testIsTrue) + } + + predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) } + } + + private import DataFlow::Global + + private int getInvalidPointerToDerefSourceDelta(DataFlow::Node node) { + exists(DataFlow::Node source | + flow(source, node) and + invalidPointerToDerefSource(_, source, result) + ) + } + + private predicate operandGuardChecks( + IRGuardCondition g, Operand left, Operand right, int state, boolean edge + ) { + exists(DataFlow::Node nLeft, DataFlow::Node nRight, int state0 | + nRight.asOperand() = right and + nLeft.asOperand() = left and + BarrierConfig::isSink(nLeft, nRight, g, state0, edge) and + state = getInvalidPointerToDerefSourceDelta(nRight) and + state0 <= state + ) + } + + Instruction getABarrierInstruction(int state) { + exists(IRGuardCondition g, ValueNumber value, Operand use, boolean edge | + use = value.getAUse() and + operandGuardChecks(pragma[only_bind_into](g), pragma[only_bind_into](use), _, state, + pragma[only_bind_into](edge)) and + result = value.getAnInstruction() and + g.controls(result.getBlock(), edge) + ) + } + + DataFlow::Node getABarrierNode() { result.asOperand() = getABarrierInstruction(_).getAUse() } + + pragma[nomagic] + IRBlock getABarrierBlock(int state) { result.getAnInstruction() = getABarrierInstruction(state) } +} + /** * A configuration to track flow from a pointer-arithmetic operation found * by `AllocToInvalidPointerConfig` to a dereference of the pointer. @@ -338,6 +394,8 @@ module InvalidPointerToDerefConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node node) { node = any(DataFlow::SsaPhiNode phi | not phi.isPhiRead()).getAnInput(true) + or + node = InvalidPointerToDerefBarrier::getABarrierNode() } } @@ -382,7 +440,7 @@ newtype TMergedPathNode = // pointer, but we want to raise an alert at the dereference. TPathNodeSink(Instruction i) { exists(DataFlow::Node n | - InvalidPointerToDerefFlow::flowTo(n) and + InvalidPointerToDerefFlow::flowTo(pragma[only_bind_into](n)) and isInvalidPointerDerefSink(n, i, _, _) and i = getASuccessor(n.asInstruction()) ) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected index c0fd4fb29dd..b1ecd38c3c3 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/InvalidPointerDeref.expected @@ -720,14 +720,6 @@ edges | test.cpp:359:16:359:27 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... | | test.cpp:359:16:359:31 | ... + ... | test.cpp:359:14:359:32 | Load: * ... | | test.cpp:363:14:363:27 | new[] | test.cpp:365:15:365:15 | p | -| test.cpp:365:15:365:15 | p | test.cpp:368:5:368:10 | ... += ... | -| test.cpp:365:15:365:15 | p | test.cpp:368:5:368:10 | ... += ... | -| test.cpp:368:5:368:10 | ... += ... | test.cpp:371:7:371:7 | p | -| test.cpp:368:5:368:10 | ... += ... | test.cpp:371:7:371:7 | p | -| test.cpp:368:5:368:10 | ... += ... | test.cpp:372:16:372:16 | p | -| test.cpp:368:5:368:10 | ... += ... | test.cpp:372:16:372:16 | p | -| test.cpp:371:7:371:7 | p | test.cpp:372:15:372:16 | Load: * ... | -| test.cpp:372:16:372:16 | p | test.cpp:372:15:372:16 | Load: * ... | | test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:16 | xs | | test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... | | test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... | @@ -752,53 +744,284 @@ edges | test.cpp:381:5:381:9 | ... ++ | test.cpp:384:14:384:16 | end | | test.cpp:384:14:384:16 | end | test.cpp:384:13:384:16 | Load: * ... | | test.cpp:388:14:388:27 | new[] | test.cpp:389:16:389:17 | xs | -| test.cpp:388:14:388:27 | new[] | test.cpp:392:5:392:6 | xs | -| test.cpp:389:16:389:17 | xs | test.cpp:392:5:392:8 | ... ++ | -| test.cpp:389:16:389:17 | xs | test.cpp:392:5:392:8 | ... ++ | -| test.cpp:389:16:389:17 | xs | test.cpp:392:5:392:8 | ... ++ | -| test.cpp:389:16:389:17 | xs | test.cpp:392:5:392:8 | ... ++ | -| test.cpp:389:16:389:17 | xs | test.cpp:393:9:393:10 | xs | -| test.cpp:389:16:389:17 | xs | test.cpp:393:9:393:10 | xs | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:392:5:392:8 | ... ++ | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:392:5:392:8 | ... ++ | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:393:9:393:10 | xs | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:393:9:393:10 | xs | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:393:9:393:10 | xs | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:393:9:393:10 | xs | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:6 | xs | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:6 | xs | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:13 | Store: ... = ... | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:13 | Store: ... = ... | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:13 | Store: ... = ... | -| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:13 | Store: ... = ... | -| test.cpp:393:9:393:10 | xs | test.cpp:395:5:395:6 | xs | -| test.cpp:393:9:393:10 | xs | test.cpp:395:5:395:13 | Store: ... = ... | -| test.cpp:393:9:393:10 | xs | test.cpp:395:5:395:13 | Store: ... = ... | -| test.cpp:395:5:395:6 | xs | test.cpp:395:5:395:13 | Store: ... = ... | -| test.cpp:406:3:406:25 | ... = ... | test.cpp:406:7:406:8 | val indirection [post update] [xs] | -| test.cpp:406:7:406:8 | val indirection [post update] [xs] | test.cpp:407:3:407:5 | val indirection [xs] | -| test.cpp:406:12:406:25 | new[] | test.cpp:406:3:406:25 | ... = ... | -| test.cpp:407:3:407:5 | val indirection [xs] | test.cpp:407:7:407:8 | xs indirection | -| test.cpp:407:7:407:8 | xs indirection | test.cpp:407:7:407:8 | xs | -| test.cpp:417:16:417:33 | new[] | test.cpp:419:7:419:8 | xs | -| test.cpp:427:14:427:27 | new[] | test.cpp:433:5:433:6 | xs | -| test.cpp:439:14:439:27 | new[] | test.cpp:444:5:444:6 | xs | -| test.cpp:450:14:450:27 | new[] | test.cpp:455:5:455:6 | xs | -| test.cpp:455:5:455:6 | xs | test.cpp:455:5:455:15 | access to array | -| test.cpp:455:5:455:15 | access to array | test.cpp:455:5:455:19 | Store: ... = ... | -| test.cpp:461:14:461:27 | new[] | test.cpp:466:5:466:6 | xs | -| test.cpp:466:5:466:6 | xs | test.cpp:466:5:466:15 | access to array | -| test.cpp:466:5:466:15 | access to array | test.cpp:466:5:466:19 | Store: ... = ... | -| test.cpp:472:14:472:27 | new[] | test.cpp:477:5:477:6 | xs | -| test.cpp:483:14:483:27 | new[] | test.cpp:488:5:488:6 | xs | -| test.cpp:494:14:494:31 | new[] | test.cpp:499:5:499:6 | xs | -| test.cpp:505:14:505:31 | new[] | test.cpp:510:5:510:6 | xs | -| test.cpp:516:14:516:31 | new[] | test.cpp:521:5:521:6 | xs | -| test.cpp:527:14:527:31 | new[] | test.cpp:532:5:532:6 | xs | -| test.cpp:538:14:538:31 | new[] | test.cpp:543:5:543:6 | xs | -| test.cpp:549:14:549:31 | new[] | test.cpp:554:5:554:6 | xs | -| test.cpp:554:5:554:6 | xs | test.cpp:554:5:554:15 | access to array | -| test.cpp:554:5:554:15 | access to array | test.cpp:554:5:554:19 | Store: ... = ... | +| test.cpp:388:14:388:27 | new[] | test.cpp:392:3:392:4 | xs | +| test.cpp:399:14:399:27 | new[] | test.cpp:400:16:400:17 | xs | +| test.cpp:399:14:399:27 | new[] | test.cpp:402:5:402:6 | xs | +| test.cpp:410:14:410:27 | new[] | test.cpp:411:16:411:17 | xs | +| test.cpp:410:14:410:27 | new[] | test.cpp:413:5:413:6 | xs | +| test.cpp:411:15:411:23 | & ... | test.cpp:411:15:411:23 | & ... | +| test.cpp:411:15:411:23 | & ... | test.cpp:411:15:411:23 | & ... | +| test.cpp:411:15:411:23 | & ... | test.cpp:412:12:412:14 | end | +| test.cpp:411:15:411:23 | & ... | test.cpp:412:12:412:14 | end | +| test.cpp:411:15:411:23 | & ... | test.cpp:412:12:412:14 | end | +| test.cpp:411:15:411:23 | & ... | test.cpp:412:12:412:14 | end | +| test.cpp:411:15:411:23 | & ... | test.cpp:414:14:414:16 | end | +| test.cpp:411:15:411:23 | & ... | test.cpp:414:14:414:16 | end | +| test.cpp:411:15:411:23 | & ... | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:411:15:411:23 | & ... | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:411:15:411:23 | & ... | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:411:15:411:23 | & ... | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:411:16:411:17 | xs | test.cpp:411:15:411:23 | & ... | +| test.cpp:411:16:411:17 | xs | test.cpp:411:15:411:23 | & ... | +| test.cpp:411:16:411:17 | xs | test.cpp:411:15:411:23 | & ... | +| test.cpp:411:16:411:17 | xs | test.cpp:411:15:411:23 | & ... | +| test.cpp:411:16:411:17 | xs | test.cpp:411:16:411:23 | access to array | +| test.cpp:411:16:411:17 | xs | test.cpp:411:16:411:23 | access to array | +| test.cpp:411:16:411:17 | xs | test.cpp:412:12:412:14 | end | +| test.cpp:411:16:411:17 | xs | test.cpp:412:12:412:14 | end | +| test.cpp:411:16:411:17 | xs | test.cpp:413:5:413:8 | ... ++ | +| test.cpp:411:16:411:17 | xs | test.cpp:413:5:413:8 | ... ++ | +| test.cpp:411:16:411:17 | xs | test.cpp:413:5:413:8 | ... ++ | +| test.cpp:411:16:411:17 | xs | test.cpp:413:5:413:8 | ... ++ | +| test.cpp:411:16:411:17 | xs | test.cpp:414:9:414:10 | xs | +| test.cpp:411:16:411:17 | xs | test.cpp:414:14:414:16 | end | +| test.cpp:411:16:411:17 | xs | test.cpp:415:7:415:11 | access to array | +| test.cpp:411:16:411:23 | access to array | test.cpp:411:15:411:23 | & ... | +| test.cpp:411:16:411:23 | access to array | test.cpp:411:15:411:23 | & ... | +| test.cpp:411:16:411:23 | access to array | test.cpp:411:15:411:23 | & ... | +| test.cpp:411:16:411:23 | access to array | test.cpp:411:15:411:23 | & ... | +| test.cpp:411:16:411:23 | access to array | test.cpp:412:12:412:14 | end | +| test.cpp:411:16:411:23 | access to array | test.cpp:412:12:412:14 | end | +| test.cpp:411:16:411:23 | access to array | test.cpp:414:14:414:16 | end | +| test.cpp:411:16:411:23 | access to array | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:411:16:411:23 | access to array | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:412:12:412:14 | end | test.cpp:414:14:414:16 | end | +| test.cpp:412:12:412:14 | end | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:412:12:412:14 | end | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:413:5:413:8 | ... ++ | test.cpp:413:5:413:8 | ... ++ | +| test.cpp:413:5:413:8 | ... ++ | test.cpp:413:5:413:8 | ... ++ | +| test.cpp:413:5:413:8 | ... ++ | test.cpp:414:9:414:10 | xs | +| test.cpp:413:5:413:8 | ... ++ | test.cpp:414:9:414:10 | xs | +| test.cpp:413:5:413:8 | ... ++ | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:413:5:413:8 | ... ++ | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:413:5:413:8 | ... ++ | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:413:5:413:8 | ... ++ | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:414:9:414:10 | xs | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:414:14:414:16 | end | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:415:7:415:11 | access to array | test.cpp:415:7:415:15 | Store: ... = ... | +| test.cpp:421:14:421:27 | new[] | test.cpp:422:16:422:17 | xs | +| test.cpp:421:14:421:27 | new[] | test.cpp:424:5:424:6 | xs | +| test.cpp:422:15:422:23 | & ... | test.cpp:422:15:422:23 | & ... | +| test.cpp:422:15:422:23 | & ... | test.cpp:422:15:422:23 | & ... | +| test.cpp:422:15:422:23 | & ... | test.cpp:423:12:423:14 | end | +| test.cpp:422:15:422:23 | & ... | test.cpp:423:12:423:14 | end | +| test.cpp:422:15:422:23 | & ... | test.cpp:423:12:423:14 | end | +| test.cpp:422:15:422:23 | & ... | test.cpp:423:12:423:14 | end | +| test.cpp:422:15:422:23 | & ... | test.cpp:425:18:425:20 | end | +| test.cpp:422:15:422:23 | & ... | test.cpp:425:18:425:20 | end | +| test.cpp:422:15:422:23 | & ... | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:422:15:422:23 | & ... | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:422:15:422:23 | & ... | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:422:15:422:23 | & ... | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:422:16:422:17 | xs | test.cpp:422:15:422:23 | & ... | +| test.cpp:422:16:422:17 | xs | test.cpp:422:15:422:23 | & ... | +| test.cpp:422:16:422:17 | xs | test.cpp:422:15:422:23 | & ... | +| test.cpp:422:16:422:17 | xs | test.cpp:422:15:422:23 | & ... | +| test.cpp:422:16:422:17 | xs | test.cpp:422:16:422:23 | access to array | +| test.cpp:422:16:422:17 | xs | test.cpp:422:16:422:23 | access to array | +| test.cpp:422:16:422:17 | xs | test.cpp:423:12:423:14 | end | +| test.cpp:422:16:422:17 | xs | test.cpp:423:12:423:14 | end | +| test.cpp:422:16:422:17 | xs | test.cpp:424:5:424:8 | ... ++ | +| test.cpp:422:16:422:17 | xs | test.cpp:424:5:424:8 | ... ++ | +| test.cpp:422:16:422:17 | xs | test.cpp:424:5:424:8 | ... ++ | +| test.cpp:422:16:422:17 | xs | test.cpp:424:5:424:8 | ... ++ | +| test.cpp:422:16:422:17 | xs | test.cpp:425:9:425:10 | xs | +| test.cpp:422:16:422:17 | xs | test.cpp:425:9:425:10 | xs | +| test.cpp:422:16:422:17 | xs | test.cpp:425:18:425:20 | end | +| test.cpp:422:16:422:17 | xs | test.cpp:426:7:426:8 | xs | +| test.cpp:422:16:422:17 | xs | test.cpp:426:7:426:11 | access to array | +| test.cpp:422:16:422:23 | access to array | test.cpp:422:15:422:23 | & ... | +| test.cpp:422:16:422:23 | access to array | test.cpp:422:15:422:23 | & ... | +| test.cpp:422:16:422:23 | access to array | test.cpp:422:15:422:23 | & ... | +| test.cpp:422:16:422:23 | access to array | test.cpp:422:15:422:23 | & ... | +| test.cpp:422:16:422:23 | access to array | test.cpp:423:12:423:14 | end | +| test.cpp:422:16:422:23 | access to array | test.cpp:423:12:423:14 | end | +| test.cpp:422:16:422:23 | access to array | test.cpp:425:18:425:20 | end | +| test.cpp:422:16:422:23 | access to array | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:422:16:422:23 | access to array | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:423:12:423:14 | end | test.cpp:425:18:425:20 | end | +| test.cpp:423:12:423:14 | end | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:423:12:423:14 | end | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:424:5:424:8 | ... ++ | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:424:5:424:8 | ... ++ | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:425:9:425:10 | xs | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:425:9:425:10 | xs | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:425:9:425:10 | xs | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:425:9:425:10 | xs | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:8 | xs | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:8 | xs | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:425:9:425:10 | xs | test.cpp:426:7:426:8 | xs | +| test.cpp:425:9:425:10 | xs | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:425:9:425:10 | xs | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:425:18:425:20 | end | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:426:7:426:8 | xs | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:426:7:426:11 | access to array | test.cpp:426:7:426:15 | Store: ... = ... | +| test.cpp:432:14:432:27 | new[] | test.cpp:433:16:433:17 | xs | +| test.cpp:432:14:432:27 | new[] | test.cpp:436:5:436:6 | xs | +| test.cpp:433:15:433:23 | & ... | test.cpp:433:15:433:23 | & ... | +| test.cpp:433:15:433:23 | & ... | test.cpp:433:15:433:23 | & ... | +| test.cpp:433:15:433:23 | & ... | test.cpp:434:12:434:14 | end | +| test.cpp:433:15:433:23 | & ... | test.cpp:434:12:434:14 | end | +| test.cpp:433:15:433:23 | & ... | test.cpp:434:12:434:14 | end | +| test.cpp:433:15:433:23 | & ... | test.cpp:434:12:434:14 | end | +| test.cpp:433:15:433:23 | & ... | test.cpp:435:5:435:7 | end | +| test.cpp:433:15:433:23 | & ... | test.cpp:435:5:435:7 | end | +| test.cpp:433:15:433:23 | & ... | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:433:15:433:23 | & ... | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:433:15:433:23 | & ... | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:433:15:433:23 | & ... | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:433:16:433:17 | xs | test.cpp:433:15:433:23 | & ... | +| test.cpp:433:16:433:17 | xs | test.cpp:433:15:433:23 | & ... | +| test.cpp:433:16:433:17 | xs | test.cpp:433:15:433:23 | & ... | +| test.cpp:433:16:433:17 | xs | test.cpp:433:15:433:23 | & ... | +| test.cpp:433:16:433:17 | xs | test.cpp:433:16:433:23 | access to array | +| test.cpp:433:16:433:17 | xs | test.cpp:433:16:433:23 | access to array | +| test.cpp:433:16:433:17 | xs | test.cpp:434:12:434:14 | end | +| test.cpp:433:16:433:17 | xs | test.cpp:434:12:434:14 | end | +| test.cpp:433:16:433:17 | xs | test.cpp:435:5:435:7 | end | +| test.cpp:433:16:433:17 | xs | test.cpp:436:5:436:8 | ... ++ | +| test.cpp:433:16:433:17 | xs | test.cpp:436:5:436:8 | ... ++ | +| test.cpp:433:16:433:17 | xs | test.cpp:436:5:436:8 | ... ++ | +| test.cpp:433:16:433:17 | xs | test.cpp:436:5:436:8 | ... ++ | +| test.cpp:433:16:433:17 | xs | test.cpp:437:9:437:10 | xs | +| test.cpp:433:16:433:17 | xs | test.cpp:438:7:438:11 | access to array | +| test.cpp:433:16:433:23 | access to array | test.cpp:433:15:433:23 | & ... | +| test.cpp:433:16:433:23 | access to array | test.cpp:433:15:433:23 | & ... | +| test.cpp:433:16:433:23 | access to array | test.cpp:433:15:433:23 | & ... | +| test.cpp:433:16:433:23 | access to array | test.cpp:433:15:433:23 | & ... | +| test.cpp:433:16:433:23 | access to array | test.cpp:434:12:434:14 | end | +| test.cpp:433:16:433:23 | access to array | test.cpp:434:12:434:14 | end | +| test.cpp:433:16:433:23 | access to array | test.cpp:435:5:435:7 | end | +| test.cpp:433:16:433:23 | access to array | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:433:16:433:23 | access to array | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:434:12:434:14 | end | test.cpp:435:5:435:7 | end | +| test.cpp:434:12:434:14 | end | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:434:12:434:14 | end | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:435:5:435:7 | end | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:436:5:436:8 | ... ++ | test.cpp:436:5:436:8 | ... ++ | +| test.cpp:436:5:436:8 | ... ++ | test.cpp:436:5:436:8 | ... ++ | +| test.cpp:436:5:436:8 | ... ++ | test.cpp:437:9:437:10 | xs | +| test.cpp:436:5:436:8 | ... ++ | test.cpp:437:9:437:10 | xs | +| test.cpp:436:5:436:8 | ... ++ | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:436:5:436:8 | ... ++ | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:436:5:436:8 | ... ++ | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:436:5:436:8 | ... ++ | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:437:9:437:10 | xs | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:438:7:438:11 | access to array | test.cpp:438:7:438:15 | Store: ... = ... | +| test.cpp:444:14:444:27 | new[] | test.cpp:445:16:445:17 | xs | +| test.cpp:444:14:444:27 | new[] | test.cpp:448:5:448:6 | xs | +| test.cpp:445:15:445:23 | & ... | test.cpp:445:15:445:23 | & ... | +| test.cpp:445:15:445:23 | & ... | test.cpp:445:15:445:23 | & ... | +| test.cpp:445:15:445:23 | & ... | test.cpp:446:3:446:5 | end | +| test.cpp:445:15:445:23 | & ... | test.cpp:446:3:446:5 | end | +| test.cpp:445:15:445:23 | & ... | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:445:15:445:23 | & ... | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:445:15:445:23 | & ... | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:445:15:445:23 | & ... | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:445:16:445:17 | xs | test.cpp:445:15:445:23 | & ... | +| test.cpp:445:16:445:17 | xs | test.cpp:445:15:445:23 | & ... | +| test.cpp:445:16:445:17 | xs | test.cpp:445:15:445:23 | & ... | +| test.cpp:445:16:445:17 | xs | test.cpp:445:15:445:23 | & ... | +| test.cpp:445:16:445:17 | xs | test.cpp:445:16:445:23 | access to array | +| test.cpp:445:16:445:17 | xs | test.cpp:445:16:445:23 | access to array | +| test.cpp:445:16:445:17 | xs | test.cpp:446:3:446:5 | end | +| test.cpp:445:16:445:17 | xs | test.cpp:448:5:448:8 | ... ++ | +| test.cpp:445:16:445:17 | xs | test.cpp:448:5:448:8 | ... ++ | +| test.cpp:445:16:445:17 | xs | test.cpp:448:5:448:8 | ... ++ | +| test.cpp:445:16:445:17 | xs | test.cpp:448:5:448:8 | ... ++ | +| test.cpp:445:16:445:17 | xs | test.cpp:449:9:449:10 | xs | +| test.cpp:445:16:445:17 | xs | test.cpp:450:7:450:11 | access to array | +| test.cpp:445:16:445:23 | access to array | test.cpp:445:15:445:23 | & ... | +| test.cpp:445:16:445:23 | access to array | test.cpp:445:15:445:23 | & ... | +| test.cpp:445:16:445:23 | access to array | test.cpp:445:15:445:23 | & ... | +| test.cpp:445:16:445:23 | access to array | test.cpp:445:15:445:23 | & ... | +| test.cpp:445:16:445:23 | access to array | test.cpp:446:3:446:5 | end | +| test.cpp:445:16:445:23 | access to array | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:445:16:445:23 | access to array | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:446:3:446:5 | end | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:448:5:448:8 | ... ++ | test.cpp:448:5:448:8 | ... ++ | +| test.cpp:448:5:448:8 | ... ++ | test.cpp:448:5:448:8 | ... ++ | +| test.cpp:448:5:448:8 | ... ++ | test.cpp:449:9:449:10 | xs | +| test.cpp:448:5:448:8 | ... ++ | test.cpp:449:9:449:10 | xs | +| test.cpp:448:5:448:8 | ... ++ | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:448:5:448:8 | ... ++ | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:448:5:448:8 | ... ++ | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:448:5:448:8 | ... ++ | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:449:9:449:10 | xs | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:450:7:450:11 | access to array | test.cpp:450:7:450:15 | Store: ... = ... | +| test.cpp:456:14:456:31 | new[] | test.cpp:457:16:457:17 | xs | +| test.cpp:456:14:456:31 | new[] | test.cpp:460:5:460:6 | xs | +| test.cpp:468:14:468:27 | new[] | test.cpp:469:16:469:17 | xs | +| test.cpp:468:14:468:27 | new[] | test.cpp:472:5:472:6 | xs | +| test.cpp:480:14:480:27 | new[] | test.cpp:481:16:481:17 | xs | +| test.cpp:480:14:480:27 | new[] | test.cpp:484:5:484:6 | xs | +| test.cpp:481:15:481:23 | & ... | test.cpp:481:15:481:23 | & ... | +| test.cpp:481:15:481:23 | & ... | test.cpp:481:15:481:23 | & ... | +| test.cpp:481:15:481:23 | & ... | test.cpp:482:3:482:5 | end | +| test.cpp:481:15:481:23 | & ... | test.cpp:482:3:482:5 | end | +| test.cpp:481:15:481:23 | & ... | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:481:15:481:23 | & ... | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:481:15:481:23 | & ... | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:481:15:481:23 | & ... | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:481:16:481:17 | xs | test.cpp:481:15:481:23 | & ... | +| test.cpp:481:16:481:17 | xs | test.cpp:481:15:481:23 | & ... | +| test.cpp:481:16:481:17 | xs | test.cpp:481:15:481:23 | & ... | +| test.cpp:481:16:481:17 | xs | test.cpp:481:15:481:23 | & ... | +| test.cpp:481:16:481:17 | xs | test.cpp:481:16:481:23 | access to array | +| test.cpp:481:16:481:17 | xs | test.cpp:481:16:481:23 | access to array | +| test.cpp:481:16:481:17 | xs | test.cpp:482:3:482:5 | end | +| test.cpp:481:16:481:17 | xs | test.cpp:484:5:484:8 | ... ++ | +| test.cpp:481:16:481:17 | xs | test.cpp:484:5:484:8 | ... ++ | +| test.cpp:481:16:481:17 | xs | test.cpp:484:5:484:8 | ... ++ | +| test.cpp:481:16:481:17 | xs | test.cpp:484:5:484:8 | ... ++ | +| test.cpp:481:16:481:17 | xs | test.cpp:485:9:485:10 | xs | +| test.cpp:481:16:481:17 | xs | test.cpp:486:7:486:11 | access to array | +| test.cpp:481:16:481:23 | access to array | test.cpp:481:15:481:23 | & ... | +| test.cpp:481:16:481:23 | access to array | test.cpp:481:15:481:23 | & ... | +| test.cpp:481:16:481:23 | access to array | test.cpp:481:15:481:23 | & ... | +| test.cpp:481:16:481:23 | access to array | test.cpp:481:15:481:23 | & ... | +| test.cpp:481:16:481:23 | access to array | test.cpp:482:3:482:5 | end | +| test.cpp:481:16:481:23 | access to array | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:481:16:481:23 | access to array | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:482:3:482:5 | end | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:484:5:484:8 | ... ++ | test.cpp:484:5:484:8 | ... ++ | +| test.cpp:484:5:484:8 | ... ++ | test.cpp:484:5:484:8 | ... ++ | +| test.cpp:484:5:484:8 | ... ++ | test.cpp:485:9:485:10 | xs | +| test.cpp:484:5:484:8 | ... ++ | test.cpp:485:9:485:10 | xs | +| test.cpp:484:5:484:8 | ... ++ | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:484:5:484:8 | ... ++ | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:484:5:484:8 | ... ++ | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:484:5:484:8 | ... ++ | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:485:9:485:10 | xs | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:486:7:486:11 | access to array | test.cpp:486:7:486:15 | Store: ... = ... | +| test.cpp:499:3:499:25 | ... = ... | test.cpp:499:7:499:8 | val indirection [post update] [xs] | +| test.cpp:499:7:499:8 | val indirection [post update] [xs] | test.cpp:500:3:500:5 | val indirection [xs] | +| test.cpp:499:12:499:25 | new[] | test.cpp:499:3:499:25 | ... = ... | +| test.cpp:500:3:500:5 | val indirection [xs] | test.cpp:500:7:500:8 | xs indirection | +| test.cpp:500:7:500:8 | xs indirection | test.cpp:500:7:500:8 | xs | +| test.cpp:510:16:510:33 | new[] | test.cpp:512:7:512:8 | xs | +| test.cpp:520:14:520:27 | new[] | test.cpp:526:5:526:6 | xs | +| test.cpp:532:14:532:27 | new[] | test.cpp:537:5:537:6 | xs | +| test.cpp:543:14:543:27 | new[] | test.cpp:548:5:548:6 | xs | +| test.cpp:548:5:548:6 | xs | test.cpp:548:5:548:15 | access to array | +| test.cpp:548:5:548:15 | access to array | test.cpp:548:5:548:19 | Store: ... = ... | +| test.cpp:554:14:554:27 | new[] | test.cpp:559:5:559:6 | xs | +| test.cpp:559:5:559:6 | xs | test.cpp:559:5:559:15 | access to array | +| test.cpp:559:5:559:15 | access to array | test.cpp:559:5:559:19 | Store: ... = ... | +| test.cpp:565:14:565:27 | new[] | test.cpp:570:5:570:6 | xs | +| test.cpp:576:14:576:27 | new[] | test.cpp:581:5:581:6 | xs | +| test.cpp:587:14:587:31 | new[] | test.cpp:592:5:592:6 | xs | +| test.cpp:598:14:598:31 | new[] | test.cpp:603:5:603:6 | xs | +| test.cpp:609:14:609:31 | new[] | test.cpp:614:5:614:6 | xs | +| test.cpp:620:14:620:31 | new[] | test.cpp:625:5:625:6 | xs | +| test.cpp:631:14:631:31 | new[] | test.cpp:636:5:636:6 | xs | +| test.cpp:642:14:642:31 | new[] | test.cpp:647:5:647:6 | xs | +| test.cpp:647:5:647:6 | xs | test.cpp:647:5:647:15 | access to array | +| test.cpp:647:5:647:15 | access to array | test.cpp:647:5:647:19 | Store: ... = ... | nodes | test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc | | test.cpp:5:15:5:15 | p | semmle.label | p | @@ -1125,11 +1348,6 @@ nodes | test.cpp:359:16:359:31 | ... + ... | semmle.label | ... + ... | | test.cpp:363:14:363:27 | new[] | semmle.label | new[] | | test.cpp:365:15:365:15 | p | semmle.label | p | -| test.cpp:368:5:368:10 | ... += ... | semmle.label | ... += ... | -| test.cpp:368:5:368:10 | ... += ... | semmle.label | ... += ... | -| test.cpp:371:7:371:7 | p | semmle.label | p | -| test.cpp:372:15:372:16 | Load: * ... | semmle.label | Load: * ... | -| test.cpp:372:16:372:16 | p | semmle.label | p | | test.cpp:377:14:377:27 | new[] | semmle.label | new[] | | test.cpp:378:15:378:16 | xs | semmle.label | xs | | test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... | @@ -1143,53 +1361,147 @@ nodes | test.cpp:384:14:384:16 | end | semmle.label | end | | test.cpp:388:14:388:27 | new[] | semmle.label | new[] | | test.cpp:389:16:389:17 | xs | semmle.label | xs | -| test.cpp:392:5:392:6 | xs | semmle.label | xs | -| test.cpp:392:5:392:8 | ... ++ | semmle.label | ... ++ | -| test.cpp:392:5:392:8 | ... ++ | semmle.label | ... ++ | -| test.cpp:392:5:392:8 | ... ++ | semmle.label | ... ++ | -| test.cpp:392:5:392:8 | ... ++ | semmle.label | ... ++ | -| test.cpp:393:9:393:10 | xs | semmle.label | xs | -| test.cpp:393:9:393:10 | xs | semmle.label | xs | -| test.cpp:395:5:395:6 | xs | semmle.label | xs | -| test.cpp:395:5:395:13 | Store: ... = ... | semmle.label | Store: ... = ... | -| test.cpp:406:3:406:25 | ... = ... | semmle.label | ... = ... | -| test.cpp:406:7:406:8 | val indirection [post update] [xs] | semmle.label | val indirection [post update] [xs] | -| test.cpp:406:12:406:25 | new[] | semmle.label | new[] | -| test.cpp:407:3:407:5 | val indirection [xs] | semmle.label | val indirection [xs] | -| test.cpp:407:7:407:8 | xs | semmle.label | xs | -| test.cpp:407:7:407:8 | xs indirection | semmle.label | xs indirection | -| test.cpp:417:16:417:33 | new[] | semmle.label | new[] | -| test.cpp:419:7:419:8 | xs | semmle.label | xs | -| test.cpp:427:14:427:27 | new[] | semmle.label | new[] | -| test.cpp:433:5:433:6 | xs | semmle.label | xs | -| test.cpp:439:14:439:27 | new[] | semmle.label | new[] | -| test.cpp:444:5:444:6 | xs | semmle.label | xs | -| test.cpp:450:14:450:27 | new[] | semmle.label | new[] | -| test.cpp:455:5:455:6 | xs | semmle.label | xs | -| test.cpp:455:5:455:15 | access to array | semmle.label | access to array | -| test.cpp:455:5:455:19 | Store: ... = ... | semmle.label | Store: ... = ... | -| test.cpp:461:14:461:27 | new[] | semmle.label | new[] | -| test.cpp:466:5:466:6 | xs | semmle.label | xs | -| test.cpp:466:5:466:15 | access to array | semmle.label | access to array | -| test.cpp:466:5:466:19 | Store: ... = ... | semmle.label | Store: ... = ... | -| test.cpp:472:14:472:27 | new[] | semmle.label | new[] | -| test.cpp:477:5:477:6 | xs | semmle.label | xs | -| test.cpp:483:14:483:27 | new[] | semmle.label | new[] | -| test.cpp:488:5:488:6 | xs | semmle.label | xs | -| test.cpp:494:14:494:31 | new[] | semmle.label | new[] | -| test.cpp:499:5:499:6 | xs | semmle.label | xs | -| test.cpp:505:14:505:31 | new[] | semmle.label | new[] | -| test.cpp:510:5:510:6 | xs | semmle.label | xs | -| test.cpp:516:14:516:31 | new[] | semmle.label | new[] | -| test.cpp:521:5:521:6 | xs | semmle.label | xs | -| test.cpp:527:14:527:31 | new[] | semmle.label | new[] | -| test.cpp:532:5:532:6 | xs | semmle.label | xs | -| test.cpp:538:14:538:31 | new[] | semmle.label | new[] | -| test.cpp:543:5:543:6 | xs | semmle.label | xs | -| test.cpp:549:14:549:31 | new[] | semmle.label | new[] | -| test.cpp:554:5:554:6 | xs | semmle.label | xs | -| test.cpp:554:5:554:15 | access to array | semmle.label | access to array | -| test.cpp:554:5:554:19 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:392:3:392:4 | xs | semmle.label | xs | +| test.cpp:399:14:399:27 | new[] | semmle.label | new[] | +| test.cpp:400:16:400:17 | xs | semmle.label | xs | +| test.cpp:402:5:402:6 | xs | semmle.label | xs | +| test.cpp:410:14:410:27 | new[] | semmle.label | new[] | +| test.cpp:411:15:411:23 | & ... | semmle.label | & ... | +| test.cpp:411:15:411:23 | & ... | semmle.label | & ... | +| test.cpp:411:15:411:23 | & ... | semmle.label | & ... | +| test.cpp:411:15:411:23 | & ... | semmle.label | & ... | +| test.cpp:411:16:411:17 | xs | semmle.label | xs | +| test.cpp:411:16:411:23 | access to array | semmle.label | access to array | +| test.cpp:411:16:411:23 | access to array | semmle.label | access to array | +| test.cpp:412:12:412:14 | end | semmle.label | end | +| test.cpp:412:12:412:14 | end | semmle.label | end | +| test.cpp:413:5:413:6 | xs | semmle.label | xs | +| test.cpp:413:5:413:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:413:5:413:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:413:5:413:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:413:5:413:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:414:9:414:10 | xs | semmle.label | xs | +| test.cpp:414:14:414:16 | end | semmle.label | end | +| test.cpp:415:7:415:11 | access to array | semmle.label | access to array | +| test.cpp:415:7:415:15 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:421:14:421:27 | new[] | semmle.label | new[] | +| test.cpp:422:15:422:23 | & ... | semmle.label | & ... | +| test.cpp:422:15:422:23 | & ... | semmle.label | & ... | +| test.cpp:422:15:422:23 | & ... | semmle.label | & ... | +| test.cpp:422:15:422:23 | & ... | semmle.label | & ... | +| test.cpp:422:16:422:17 | xs | semmle.label | xs | +| test.cpp:422:16:422:23 | access to array | semmle.label | access to array | +| test.cpp:422:16:422:23 | access to array | semmle.label | access to array | +| test.cpp:423:12:423:14 | end | semmle.label | end | +| test.cpp:423:12:423:14 | end | semmle.label | end | +| test.cpp:424:5:424:6 | xs | semmle.label | xs | +| test.cpp:424:5:424:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:424:5:424:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:424:5:424:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:424:5:424:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:425:9:425:10 | xs | semmle.label | xs | +| test.cpp:425:9:425:10 | xs | semmle.label | xs | +| test.cpp:425:18:425:20 | end | semmle.label | end | +| test.cpp:426:7:426:8 | xs | semmle.label | xs | +| test.cpp:426:7:426:11 | access to array | semmle.label | access to array | +| test.cpp:426:7:426:15 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:432:14:432:27 | new[] | semmle.label | new[] | +| test.cpp:433:15:433:23 | & ... | semmle.label | & ... | +| test.cpp:433:15:433:23 | & ... | semmle.label | & ... | +| test.cpp:433:15:433:23 | & ... | semmle.label | & ... | +| test.cpp:433:15:433:23 | & ... | semmle.label | & ... | +| test.cpp:433:16:433:17 | xs | semmle.label | xs | +| test.cpp:433:16:433:23 | access to array | semmle.label | access to array | +| test.cpp:433:16:433:23 | access to array | semmle.label | access to array | +| test.cpp:434:12:434:14 | end | semmle.label | end | +| test.cpp:434:12:434:14 | end | semmle.label | end | +| test.cpp:435:5:435:7 | end | semmle.label | end | +| test.cpp:436:5:436:6 | xs | semmle.label | xs | +| test.cpp:436:5:436:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:436:5:436:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:436:5:436:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:436:5:436:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:437:9:437:10 | xs | semmle.label | xs | +| test.cpp:438:7:438:11 | access to array | semmle.label | access to array | +| test.cpp:438:7:438:15 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:444:14:444:27 | new[] | semmle.label | new[] | +| test.cpp:445:15:445:23 | & ... | semmle.label | & ... | +| test.cpp:445:15:445:23 | & ... | semmle.label | & ... | +| test.cpp:445:15:445:23 | & ... | semmle.label | & ... | +| test.cpp:445:15:445:23 | & ... | semmle.label | & ... | +| test.cpp:445:16:445:17 | xs | semmle.label | xs | +| test.cpp:445:16:445:23 | access to array | semmle.label | access to array | +| test.cpp:445:16:445:23 | access to array | semmle.label | access to array | +| test.cpp:446:3:446:5 | end | semmle.label | end | +| test.cpp:448:5:448:6 | xs | semmle.label | xs | +| test.cpp:448:5:448:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:448:5:448:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:448:5:448:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:448:5:448:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:449:9:449:10 | xs | semmle.label | xs | +| test.cpp:450:7:450:11 | access to array | semmle.label | access to array | +| test.cpp:450:7:450:15 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:456:14:456:31 | new[] | semmle.label | new[] | +| test.cpp:457:16:457:17 | xs | semmle.label | xs | +| test.cpp:460:5:460:6 | xs | semmle.label | xs | +| test.cpp:468:14:468:27 | new[] | semmle.label | new[] | +| test.cpp:469:16:469:17 | xs | semmle.label | xs | +| test.cpp:472:5:472:6 | xs | semmle.label | xs | +| test.cpp:480:14:480:27 | new[] | semmle.label | new[] | +| test.cpp:481:15:481:23 | & ... | semmle.label | & ... | +| test.cpp:481:15:481:23 | & ... | semmle.label | & ... | +| test.cpp:481:15:481:23 | & ... | semmle.label | & ... | +| test.cpp:481:15:481:23 | & ... | semmle.label | & ... | +| test.cpp:481:16:481:17 | xs | semmle.label | xs | +| test.cpp:481:16:481:23 | access to array | semmle.label | access to array | +| test.cpp:481:16:481:23 | access to array | semmle.label | access to array | +| test.cpp:482:3:482:5 | end | semmle.label | end | +| test.cpp:484:5:484:6 | xs | semmle.label | xs | +| test.cpp:484:5:484:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:484:5:484:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:484:5:484:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:484:5:484:8 | ... ++ | semmle.label | ... ++ | +| test.cpp:485:9:485:10 | xs | semmle.label | xs | +| test.cpp:486:7:486:11 | access to array | semmle.label | access to array | +| test.cpp:486:7:486:15 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:499:3:499:25 | ... = ... | semmle.label | ... = ... | +| test.cpp:499:7:499:8 | val indirection [post update] [xs] | semmle.label | val indirection [post update] [xs] | +| test.cpp:499:12:499:25 | new[] | semmle.label | new[] | +| test.cpp:500:3:500:5 | val indirection [xs] | semmle.label | val indirection [xs] | +| test.cpp:500:7:500:8 | xs | semmle.label | xs | +| test.cpp:500:7:500:8 | xs indirection | semmle.label | xs indirection | +| test.cpp:510:16:510:33 | new[] | semmle.label | new[] | +| test.cpp:512:7:512:8 | xs | semmle.label | xs | +| test.cpp:520:14:520:27 | new[] | semmle.label | new[] | +| test.cpp:526:5:526:6 | xs | semmle.label | xs | +| test.cpp:532:14:532:27 | new[] | semmle.label | new[] | +| test.cpp:537:5:537:6 | xs | semmle.label | xs | +| test.cpp:543:14:543:27 | new[] | semmle.label | new[] | +| test.cpp:548:5:548:6 | xs | semmle.label | xs | +| test.cpp:548:5:548:15 | access to array | semmle.label | access to array | +| test.cpp:548:5:548:19 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:554:14:554:27 | new[] | semmle.label | new[] | +| test.cpp:559:5:559:6 | xs | semmle.label | xs | +| test.cpp:559:5:559:15 | access to array | semmle.label | access to array | +| test.cpp:559:5:559:19 | Store: ... = ... | semmle.label | Store: ... = ... | +| test.cpp:565:14:565:27 | new[] | semmle.label | new[] | +| test.cpp:570:5:570:6 | xs | semmle.label | xs | +| test.cpp:576:14:576:27 | new[] | semmle.label | new[] | +| test.cpp:581:5:581:6 | xs | semmle.label | xs | +| test.cpp:587:14:587:31 | new[] | semmle.label | new[] | +| test.cpp:592:5:592:6 | xs | semmle.label | xs | +| test.cpp:598:14:598:31 | new[] | semmle.label | new[] | +| test.cpp:603:5:603:6 | xs | semmle.label | xs | +| test.cpp:609:14:609:31 | new[] | semmle.label | new[] | +| test.cpp:614:5:614:6 | xs | semmle.label | xs | +| test.cpp:620:14:620:31 | new[] | semmle.label | new[] | +| test.cpp:625:5:625:6 | xs | semmle.label | xs | +| test.cpp:631:14:631:31 | new[] | semmle.label | new[] | +| test.cpp:636:5:636:6 | xs | semmle.label | xs | +| test.cpp:642:14:642:31 | new[] | semmle.label | new[] | +| test.cpp:647:5:647:6 | xs | semmle.label | xs | +| test.cpp:647:5:647:15 | access to array | semmle.label | access to array | +| test.cpp:647:5:647:19 | Store: ... = ... | semmle.label | Store: ... = ... | subpaths #select | test.cpp:6:14:6:15 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size | @@ -1214,9 +1526,12 @@ subpaths | test.cpp:308:5:308:29 | Store: ... = ... | test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308:29 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:304:15:304:26 | new[] | new[] | test.cpp:308:8:308:10 | ... + ... | ... + ... | | test.cpp:358:14:358:26 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | | test.cpp:359:14:359:32 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 2. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size | -| test.cpp:372:15:372:16 | Load: * ... | test.cpp:363:14:363:27 | new[] | test.cpp:372:15:372:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:363:14:363:27 | new[] | new[] | test.cpp:365:19:365:22 | size | size | | test.cpp:384:13:384:16 | Load: * ... | test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:377:14:377:27 | new[] | new[] | test.cpp:378:20:378:23 | size | size | -| test.cpp:395:5:395:13 | Store: ... = ... | test.cpp:388:14:388:27 | new[] | test.cpp:395:5:395:13 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:388:14:388:27 | new[] | new[] | test.cpp:389:19:389:22 | size | size | -| test.cpp:455:5:455:19 | Store: ... = ... | test.cpp:450:14:450:27 | new[] | test.cpp:455:5:455:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:450:14:450:27 | new[] | new[] | test.cpp:455:8:455:14 | src_pos | src_pos | -| test.cpp:466:5:466:19 | Store: ... = ... | test.cpp:461:14:461:27 | new[] | test.cpp:466:5:466:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:461:14:461:27 | new[] | new[] | test.cpp:466:8:466:14 | src_pos | src_pos | -| test.cpp:554:5:554:19 | Store: ... = ... | test.cpp:549:14:549:31 | new[] | test.cpp:554:5:554:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:549:14:549:31 | new[] | new[] | test.cpp:554:8:554:14 | src_pos | src_pos | +| test.cpp:415:7:415:15 | Store: ... = ... | test.cpp:410:14:410:27 | new[] | test.cpp:415:7:415:15 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:410:14:410:27 | new[] | new[] | test.cpp:411:19:411:22 | size | size | +| test.cpp:426:7:426:15 | Store: ... = ... | test.cpp:421:14:421:27 | new[] | test.cpp:426:7:426:15 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:421:14:421:27 | new[] | new[] | test.cpp:422:19:422:22 | size | size | +| test.cpp:438:7:438:15 | Store: ... = ... | test.cpp:432:14:432:27 | new[] | test.cpp:438:7:438:15 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:432:14:432:27 | new[] | new[] | test.cpp:433:19:433:22 | size | size | +| test.cpp:450:7:450:15 | Store: ... = ... | test.cpp:444:14:444:27 | new[] | test.cpp:450:7:450:15 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:444:14:444:27 | new[] | new[] | test.cpp:445:19:445:22 | size | size | +| test.cpp:486:7:486:15 | Store: ... = ... | test.cpp:480:14:480:27 | new[] | test.cpp:486:7:486:15 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@ + 498. | test.cpp:480:14:480:27 | new[] | new[] | test.cpp:481:19:481:22 | size | size | +| test.cpp:548:5:548:19 | Store: ... = ... | test.cpp:543:14:543:27 | new[] | test.cpp:548:5:548:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:543:14:543:27 | new[] | new[] | test.cpp:548:8:548:14 | src_pos | src_pos | +| test.cpp:559:5:559:19 | Store: ... = ... | test.cpp:554:14:554:27 | new[] | test.cpp:559:5:559:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:554:14:554:27 | new[] | new[] | test.cpp:559:8:559:14 | src_pos | src_pos | +| test.cpp:647:5:647:19 | Store: ... = ... | test.cpp:642:14:642:31 | new[] | test.cpp:647:5:647:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:642:14:642:31 | new[] | new[] | test.cpp:647:8:647:14 | src_pos | src_pos | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp index 95af0938286..bdd3863544f 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp @@ -387,12 +387,105 @@ void test27(unsigned size, bool b) { void test28(unsigned size) { char *xs = new char[size]; char *end = &xs[size]; - if (xs >= end) - return; + if (xs >= end) + return; + xs++; + if (xs >= end) + return; + xs[0] = 0; // GOOD +} + +void test28_simple(unsigned size) { + char *xs = new char[size]; + char *end = &xs[size]; + if (xs < end) { xs++; - if (xs >= end) - return; - xs[0] = 0; // GOOD [FALSE POSITIVE] + if (xs < end) { + xs[0] = 0; // GOOD + } + } +} + +void test28_simple2(unsigned size) { + char *xs = new char[size]; + char *end = &xs[size]; + if (xs < end) { + xs++; + if (xs < end + 1) { + xs[0] = 0; // BAD + } + } +} + +void test28_simple3(unsigned size) { + char *xs = new char[size]; + char *end = &xs[size]; + if (xs < end) { + xs++; + if (xs - 1 < end) { + xs[0] = 0; // BAD + } + } +} + +void test28_simple4(unsigned size) { + char *xs = new char[size]; + char *end = &xs[size]; + if (xs < end) { + end++; + xs++; + if (xs < end) { + xs[0] = 0; // BAD + } + } +} + +void test28_simple5(unsigned size) { + char *xs = new char[size]; + char *end = &xs[size]; + end++; + if (xs < end) { + xs++; + if (xs < end) { + xs[0] = 0; // BAD + } + } +} + +void test28_simple6(unsigned size) { + char *xs = new char[size + 1]; + char *end = &xs[size]; + end++; + if (xs < end) { + xs++; + if (xs < end) { + xs[0] = 0; // GOOD + } + } +} + +void test28_simple7(unsigned size) { + char *xs = new char[size]; + char *end = &xs[size]; + end++; + if (xs < end) { + xs++; + if (xs < end - 1) { + xs[0] = 0; // GOOD + } + } +} + +void test28_simple8(unsigned size) { + char *xs = new char[size]; + char *end = &xs[size]; + end += 500; + if (xs < end) { + xs++; + if (xs < end - 1) { + xs[0] = 0; // BAD + } + } } struct test29_struct { @@ -429,7 +522,7 @@ void test31(unsigned size, unsigned src_pos) src_pos = size; } unsigned dst_pos = src_pos; - if(dst_pos < size - 3) { + if (dst_pos < size - 3) { xs[dst_pos++] = 0; // GOOD } } @@ -440,7 +533,7 @@ void test31_simple1(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos < size) { + if (src_pos < size) { xs[src_pos] = 0; // GOOD } } @@ -451,7 +544,7 @@ void test31_simple2(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos < size + 1) { + if (src_pos < size + 1) { xs[src_pos] = 0; // BAD } } @@ -462,7 +555,7 @@ void test31_simple3(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos - 1 < size) { + if (src_pos - 1 < size) { xs[src_pos] = 0; // BAD } } @@ -473,7 +566,7 @@ void test31_simple4(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos < size - 1) { + if (src_pos < size - 1) { xs[src_pos] = 0; // GOOD } } @@ -484,7 +577,7 @@ void test31_simple5(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos + 1 < size) { + if (src_pos + 1 < size) { xs[src_pos] = 0; // GOOD } } @@ -495,7 +588,7 @@ void test31_simple1_plus1(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos < size) { + if (src_pos < size) { xs[src_pos] = 0; // GOOD } } @@ -506,7 +599,7 @@ void test31_simple2_plus1(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos < size + 1) { + if (src_pos < size + 1) { xs[src_pos] = 0; // GOOD } } @@ -517,7 +610,7 @@ void test31_simple3_plus1(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos - 1 < size) { + if (src_pos - 1 < size) { xs[src_pos] = 0; // GOOD } } @@ -528,7 +621,7 @@ void test31_simple4_plus1(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos < size - 1) { + if (src_pos < size - 1) { xs[src_pos] = 0; // GOOD } } @@ -539,7 +632,7 @@ void test31_simple5_plus1(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos + 1 < size) { + if (src_pos + 1 < size) { xs[src_pos] = 0; // GOOD } } @@ -550,7 +643,7 @@ void test31_simple1_sub1(unsigned size, unsigned src_pos) if (src_pos > size) { src_pos = size; } - if(src_pos < size) { + if (src_pos < size) { xs[src_pos] = 0; // BAD } } From a50d804ad710e0e314afc823ae2c10f334be8655 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Wed, 28 Jun 2023 13:48:43 +0100 Subject: [PATCH 363/364] Kotlin: Remove a use of ObsoleteDescriptorBasedAPI This isn't supported in Kotlin 2 mode, but removing this code doesn't affect any tests. --- .../src/main/kotlin/KotlinFileExtractor.kt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index 6e5d921a406..ef7fafc913a 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -157,21 +157,10 @@ open class KotlinFileExtractor( else -> false } - @OptIn(ObsoleteDescriptorBasedAPI::class) private fun isFake(d: IrDeclarationWithVisibility): Boolean { val hasFakeVisibility = d.visibility.let { it is DelegatedDescriptorVisibility && it.delegate == Visibilities.InvisibleFake } || d.isFakeOverride if (hasFakeVisibility && !isJavaBinaryObjectMethodRedeclaration(d)) return true - try { - if ((d as? IrFunction)?.descriptor?.isHiddenToOvercomeSignatureClash == true) { - return true - } - } - catch (e: NotImplementedError) { - // `org.jetbrains.kotlin.ir.descriptors.IrBasedClassConstructorDescriptor.isHiddenToOvercomeSignatureClash` throws the exception - logger.warnElement("Couldn't query if element is fake, deciding it's not.", d, e) - return false - } return false } From 527b908bdaa011554e0d00eef1b9b21fe7ca8909 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 28 Jun 2023 17:54:12 +0200 Subject: [PATCH 364/364] C++: Fix test annotation for `cpp/invalid-pointer-deref` test --- .../query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp index bdd3863544f..b10a2775fb2 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-193/pointer-deref/test.cpp @@ -369,7 +369,7 @@ void test26(unsigned size) { } if (p < end) { - int val = *p; // GOOD [FALSE POSITIVE] + int val = *p; // GOOD } }